diff --git a/src/App.js b/src/App.js index 68565d2..08930ba 100644 --- a/src/App.js +++ b/src/App.js @@ -109,6 +109,31 @@ import { } from './screens/Wa/Manage'; import { CreateSettings } from './screens/Wa/Manage/Content'; +import { + Settings as SettingsWa, + Summary as SummaryActivityWa, + Transaction as TransactionLogsWa, + Bulk as BulkWa +} from './screens/Wa/Activity'; + +import { + Authentication as WaSettingsAuth, + Message as WaSettingsMessage, + Transaction as WaSummaryTransaction, + Announcement as WaSummaryAnnouncement, + Conversation as WaSummaryConversation, + AuthLogs as WaTransactionAuth, + MessageLogs as WaTransactionMessage +} from './screens/Wa/Activity/Section'; + +import { + Inbox as InboxWa +} from './screens/Wa/Inbox'; + +import { + Block as BlockedWa +} from './screens/Wa/Block'; + const App = () => { return ( @@ -220,6 +245,39 @@ const App = () => { } /> } /> } /> + + {/* WhatsApp - Activity (Settings) */} + }> + {/* Anak rute */} + } /> + } /> + {/* Default route */} + } /> + + + {/* WhatsApp - Activity (Summary) */} + }> + {/* Anak rute */} + } /> + } /> + } /> + {/* Default route */} + } /> + + + {/* WhatsApp - Activity (Transaction) */} + }> + {/* Anak rute */} + } /> + } /> + {/* Default route */} + } /> + + + } /> + + } /> + } /> {/* } /> */} {/* Continue for each link */} diff --git a/src/components/Sidebar/dataMenu.js b/src/components/Sidebar/dataMenu.js index 238990c..3b8c7b6 100644 --- a/src/components/Sidebar/dataMenu.js +++ b/src/components/Sidebar/dataMenu.js @@ -147,10 +147,10 @@ const dataMenu = [ name: 'WhatsApp Activity', // Changed the name target: 'collapseActivity', subMenus: [ - { name: 'Settings', link: '/wa-activity-settings'}, // Changed the name - { name: 'Activity Summary', link: '/wa-activity-summary'}, // Changed the name - { name: 'Transaction Logs', link: '/wa-activity-transaction'}, - { name: 'Bulk Sending', link: '/wa-activity-bulk'}, // Changed the name + { name: 'Settings', link: '/wa-settings'}, // Changed the name + { name: 'Activity Summary', link: '/wa-summary'}, // Changed the name + { name: 'Transaction Logs', link: '/wa-transaction'}, + { name: 'Bulk Sending', link: '/wa-bulk'}, // Changed the name ], }, { diff --git a/src/screens/Wa/Activity/Bulk.jsx b/src/screens/Wa/Activity/Bulk.jsx new file mode 100644 index 0000000..7fe1a24 --- /dev/null +++ b/src/screens/Wa/Activity/Bulk.jsx @@ -0,0 +1,181 @@ +import React, { useState, useEffect } from 'react' + +const Bulk = () => { + const [isMobile, setIsMobile] = useState(window.innerWidth <= 768); + + useEffect(() => { + const handleResize = () => setIsMobile(window.innerWidth <= 768); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + return ( +
+
+
+

+ Tips: Need Guidance to create template?{' '} + + Click here + +

+
+ + +
+
+ + +
+
+

Drag and Drop Here

+

OR

+ +

+ Recommended size: 640 x 360px
+ Max size: 5MB
+ Supported file types: jpeg, png +

+
+ + +
+
+

Preview:

+ {/* Preview content */} +
+
+
+ ); +} + +export default Bulk + +const styles = { + container: { + padding: '1rem', + width: '100%', + margin: '0 auto', + boxSizing: 'border-box', + }, + // Container styles for desktop and mobile + desktopContainer: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', + gap: '1rem', + }, + mobileContainer: { + display: 'flex', + flexDirection: 'column', + gap: '1rem', + }, + wrapper: { + flex: 1, + border: '1px solid #ddd', + borderRadius: '8px', + padding: '1.5rem', + boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)', + backgroundColor: '#fff', + borderLeft: '5px solid #0542cc', + }, + previewBox: { + flex: 1, + border: '1px solid #ddd', + borderRadius: '8px', + padding: '1.5rem', + boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)', + backgroundColor: '#fff', + borderLeft: '5px solid #0542cc', + }, + tips: { + fontSize: '0.9rem', + marginBottom: '1rem', + color: '#555', + }, + link: { + color: '#0542cc', + textDecoration: 'none', + }, + formGroup: { + marginBottom: '1rem', + }, + label: { + display: 'block', + marginBottom: '0.5rem', + fontWeight: 'bold', + color: '#333', + }, + select: { + width: '100%', + padding: '0.5rem', + border: '1px solid #ccc', + borderRadius: '4px', + fontSize: '1rem', + }, + uploadBox: { + textAlign: 'center', + padding: '2rem', + border: '2px dashed #ccc', + borderRadius: '8px', + backgroundColor: '#f9f9f9', + marginBottom: '1rem', + }, + uploadText: { + fontSize: '1.2rem', + fontWeight: 'bold', + color: '#333', + }, + orText: { + margin: '0.5rem 0', + color: '#555', + }, + browseButton: { + padding: '0.5rem 1rem', + backgroundColor: '#0542cc', + color: '#fff', + border: 'none', + borderRadius: '4px', + cursor: 'pointer', + }, + uploadInfo: { + fontSize: '0.8rem', + color: '#777', + marginTop: '1rem', + }, + download: { + textAlign: 'right', + marginBottom: '1rem', + }, + downloadLink: { + color: '#0542cc', + textDecoration: 'none', + }, + demoButton: { + display: 'block', + width: '100%', + padding: '0.8rem', + backgroundColor: '#0542cc', + color: '#fff', + border: 'none', + borderRadius: '4px', + cursor: 'pointer', + fontSize: '1rem', + fontWeight: 'bold', + }, + previewTitle: { + marginBottom: '1rem', + fontWeight: 'bold', + color: '#333', + }, +}; + + diff --git a/src/screens/Wa/Activity/Section/Announcement.jsx b/src/screens/Wa/Activity/Section/Announcement.jsx new file mode 100644 index 0000000..168e81b --- /dev/null +++ b/src/screens/Wa/Activity/Section/Announcement.jsx @@ -0,0 +1,242 @@ +import React, { useState, useEffect } from 'react'; +import { + Extract, + Quality, + AsyncIcon, + QualityAsync, + Transaction as TransactionIcon, +} from '../../../../assets/icon'; + +const Announcement = () => { + const [startDate, setStartDate] = useState(''); + const [endDate, setEndDate] = useState(''); + const [application, setApplication] = useState(''); + const [isMobile, setIsMobile] = useState(false); + + const menuData = [ + { id: 1, value: '150', label: 'Total Transaction', icon: TransactionIcon }, + { id: 2, value: '4', label: 'Total Extract', icon: Extract }, + { id: 3, value: '65', label: 'Total Quality', icon: Quality }, + { id: 6, value: '900', label: 'Total Extract Async', icon: AsyncIcon }, + { id: 4, value: '22', label: 'Total Quality Async', icon: QualityAsync }, + ]; + + const handleApply = () => { + console.log({ startDate, endDate, application }); + }; + + const handleCancel = () => { + setStartDate(''); + setEndDate(''); + setApplication(''); + }; + + // Detect if the device is mobile based on window width + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth <= 768); // Define mobile screen as width <= 768px + }; + + // Initialize on component mount + handleResize(); + + // Add event listener to update state on resize + window.addEventListener('resize', handleResize); + + // Cleanup event listener on component unmount + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + return ( +
+
+ {/* Row 1: Start Date and End Date */} +
+ setStartDate(e.target.value)} + style={styles.filterInput} + placeholder="Start Date" + /> + setEndDate(e.target.value)} + style={styles.filterInput} + placeholder="End Date" + /> +
+ + {/* Row 2: Application Select */} +
+ +
+ + {/* Row 3: Apply and Cancel Buttons */} +
+ + +
+
+ +
+ {menuData.map((item) => ( +
+
+

{item.value}

+

{item.label}

+
+
+ {item.label} +
+
+ ))} +
+
+ ); +}; + +const styles = { + container: { + margin: '3rem', + }, + filters: { + display: 'flex', + justifyContent: 'space-between', + marginBottom: '20px', + flexDirection: 'row', // Horizontal layout on desktop + gap: '10px', + }, + filtersMobile: { + display: 'flex', + flexDirection: 'column', // Vertical layout on mobile + gap: '15px', + }, + filterRow: { + display: 'flex', + justifyContent: 'space-between', + gap: '10px', + width: '100%', + }, + filterInput: { + padding: '10px', + border: '1px solid #ccc', + borderRadius: '5px', + fontSize: '16px', + width: '48%', // Adjust width to take up 48% of the row for input elements + }, + applyButton: { + backgroundColor: '#0542cc', + color: '#fff', + padding: '10px 20px', + border: 'none', + borderRadius: '5px', + cursor: 'pointer', + width: '48%', // Adjust button width to take half of the row + }, + cancelButton: { + backgroundColor: '#fff', + color: '#000', + padding: '10px 20px', + border: '1px solid gray', + borderRadius: '5px', + cursor: 'pointer', + width: '48%', // Adjust button width to take half of the row + }, + summaryCards: { + display: 'grid', + gridTemplateColumns: 'repeat(4, 1fr)', // 4 columns on desktop + gap: '20px', + marginTop: '20px', + }, + summaryCardsMobile: { + display: 'grid', + gridTemplateColumns: '1fr', // 1 column on mobile (full width) + gap: '15px', + marginTop: '20px', + }, + card: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + padding: '15px', // Reduced padding for a more compact card + backgroundColor: 'white', + borderRadius: '8px', // Slightly smaller border-radius for a sharper look + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)', + textAlign: 'left', + minWidth: '200px', // Ensure minimum width for mobile responsiveness + maxWidth: '300px', // Limit the maximum width to prevent cards from becoming too wide + width: '100%', + transition: 'transform 0.3s ease', // Smooth transition for hover effects + }, + cardHover: { + transform: 'scale(1.05)', // Slight zoom on hover for interactivity + }, + iconContainer: { + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + }, + textContainer: { + display: 'flex', + flexDirection: 'column', + }, + icon: { + width: '36px', // Smaller icon size for a more compact card + height: '36px', // Matching height for the icon + }, + cardTitle: { + fontSize: '18px', // Smaller font size for title to prevent overflow + margin: '0', + fontWeight: 'bold', + }, + cardText: { + fontSize: '12px', // Smaller text size for description to keep it balanced + color: '#555', + }, + + // Optional: Hover effect for the cards to enhance interactivity + cardHover: { + transform: 'scale(1.05)', // Slight zoom effect when hovering over card + }, + + // Media query for smaller screens (e.g., phones in portrait mode) + "@media (max-width: 768px)": { + summaryCards: { + gridTemplateColumns: '1fr', // 1 column on mobile screens + }, + card: { + padding: '10px', // Smaller padding for smaller screens + minWidth: '180px', // Adjust min width for mobile devices + maxWidth: '250px', // Adjust max width for mobile devices + }, + icon: { + width: '30px', // Slightly smaller icon size for mobile + height: '30px', // Matching height for mobile icon + }, + cardTitle: { + fontSize: '16px', // Smaller font size for the card title + }, + cardText: { + fontSize: '10px', // Smaller font size for card description + }, + }, +}; + +export default Announcement; diff --git a/src/screens/Wa/Activity/Section/AuthLogs.jsx b/src/screens/Wa/Activity/Section/AuthLogs.jsx new file mode 100644 index 0000000..a2eb3e0 --- /dev/null +++ b/src/screens/Wa/Activity/Section/AuthLogs.jsx @@ -0,0 +1,429 @@ +import React, { useState, useEffect } from 'react'; +import { FaChevronLeft, FaChevronRight, FaFastBackward, FaFastForward, FaSort, FaSortUp, FaSortDown } from 'react-icons/fa'; // Icons for sorting +import { NoAvailable } from '../../../../assets/icon'; + +// Pagination Component +const Pagination = ({ currentPage, totalPages, onPageChange }) => { + const handlePrev = () => { + if (currentPage > 1) { + onPageChange(currentPage - 1); + } + }; + + const handleNext = () => { + if (currentPage < totalPages) { + onPageChange(currentPage + 1); + } + }; + + const handleFirst = () => { + onPageChange(1); // Go to first page + }; + + const handleLast = () => { + onPageChange(totalPages); // Go to last page + }; + + // Logic to display only 3 pages in pagination + const getPaginationRange = () => { + const range = []; + const totalPagesCount = totalPages; + + let start = currentPage - 1; + let end = currentPage + 1; + + // Adjust start and end if near the boundaries + if (currentPage === 1) { + start = 1; + end = Math.min(3, totalPagesCount); + } else if (currentPage === totalPages) { + start = Math.max(totalPagesCount - 2, 1); + end = totalPagesCount; + } + + for (let i = start; i <= end; i++) { + range.push(i); + } + + return range; + }; + + const pageRange = getPaginationRange(); + + return ( +
+ {/* First Page Button */} + + + + + {/* Page Numbers */} + {pageRange.map((pageNum) => ( + + ))} + + + + {/* Last Page Button */} + +
+ ); +}; + +const AuthLogs = () => { + const [currentPage, setCurrentPage] = useState(1); + const [isMobile, setIsMobile] = useState(false); // State to detect mobile view + const [transactionData, setTransactionData] = useState([]); + const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); // Sorting state + const dataPerPage = 10; // Data per page (10 data per page) + + const buttonData = [ + { label: 'Copy', enabled: true }, + { label: 'CSV', enabled: true }, + { label: 'Excel', enabled: true }, + { label: 'PDF', enabled: true }, + { label: 'Print', enabled: true }, + { label: 'Column Visibility', enabled: true }, + ]; + + + // Generate 691 dummy transactions + const generateDummyData = (numOfItems) => { + const transactionData = []; + + for (let i = 1; i <= numOfItems; i++) { + transactionData.push({ + transactionId: `TX${String(i).padStart(3, '0')}`, // Transaction ID + applicationName: `App ${Math.floor(Math.random() * 5) + 1}`, // Application Name + templateName: `Template ${Math.floor(Math.random() * 10) + 1}`, // Random Template Name + language: ['English', 'Indonesian', 'Spanish', 'French'][Math.floor(Math.random() * 4)], // Random Language + category: ['Marketing', 'Transaction', 'Alert', 'Notification'][Math.floor(Math.random() * 4)], // Random Category + dateSent: new Date(2023, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1).toLocaleDateString(), // Random Date + destinationNumber: `+62${Math.floor(Math.random() * 900000000) + 800000000}`, // Random Destination Number + mode: Math.random() > 0.5 ? 'Online' : 'Offline', // Random Mode + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], // Random Status + }); + } + + + return transactionData; + }; + + + // Set the generated transaction data + useEffect(() => { + setTransactionData(generateDummyData(31)); // count data dummy transactions + }, []); + + // Sorting function + const sortData = (data, config) => { + const { key, direction } = config; + return [...data].sort((a, b) => { + if (a[key] < b[key]) { + return direction === 'asc' ? -1 : 1; + } + if (a[key] > b[key]) { + return direction === 'asc' ? 1 : -1; + } + return 0; + }); + }; + + // Handle column header sort click + const handleSort = (key) => { + let direction = 'asc'; + if (sortConfig.key === key && sortConfig.direction === 'asc') { + direction = 'desc'; // Toggle direction if the same column is clicked + } + setSortConfig({ key, direction }); + }; + + // Get the paginated data + const getPaginatedData = (data, page, perPage) => { + const sortedData = sortData(data, sortConfig); + const startIndex = (page - 1) * perPage; + const endIndex = startIndex + perPage; + return sortedData.slice(startIndex, endIndex); + }; + + // Handle page change + const handlePageChange = (page) => { + setCurrentPage(page); + }; + + // Calculate total pages based on the data and data per page + const totalPages = Math.ceil(transactionData.length / dataPerPage); + + // Paginated data + const paginatedData = getPaginatedData(transactionData, currentPage, dataPerPage); + + // Detect screen size and update isMobile state + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth <= 768); // Change 768 to your breakpoint + }; + + handleResize(); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + return ( +
+ {/* Filter Form */} +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + {/* Action Buttons */} +
+
+ {buttonData.map((button, index) => + button.enabled ? ( + + ) : null + )} +
+ + {/* Search Bar with Icon */} +
+ + + {/* FontAwesome search icon */} + +
+
+ + {/* Table */} +
+ + + + {/* Kolom untuk Nomor Urut */} + + + + + + + + + + + + + + {paginatedData.length > 0 ? ( + paginatedData.map((transaction, index) => ( + + {/* Kolom Nomor Urut */} + + + + + + + + + + + + )) + ) : ( + + + + )} + +
No. + + + + + + + + + + + + + + + + + +
{(currentPage - 1) * dataPerPage + index + 1}{transaction.transactionId}{transaction.applicationName}{transaction.templateName}{transaction.language}{transaction.category}{transaction.dateSent}{transaction.destinationNumber}{transaction.mode}{transaction.status}
+
+ No Data Available +

Data not available

+
+
+
+ + {/* Pagination */} + +
+ ); +}; + +export default AuthLogs; + +const styles = { + tableContainer: { + minHeight: '300px', + maxHeight: '1500px', + overflowY: 'auto', + }, + iconStyle: { + width: '50px', + height: '50px', + }, + // Add margin-left style for icons + iconMarginLeft: { + marginLeft: '0.5rem', + verticalAlign: 'middle', + }, + buttonStyle: { + display: 'inline-flex', + justifyContent: 'flex-start', + alignItems: 'center', + padding: '0.5rem 1rem', + }, + actionButton: { + borderColor: '#000', + border: '1px solid black', + margin: '0 8px 8px 0', + padding: '8px 16px', + } +}; + diff --git a/src/screens/Wa/Activity/Section/Authentication.jsx b/src/screens/Wa/Activity/Section/Authentication.jsx new file mode 100644 index 0000000..55bc915 --- /dev/null +++ b/src/screens/Wa/Activity/Section/Authentication.jsx @@ -0,0 +1,126 @@ +import React from "react"; + +const Authentication = () => { + + return ( +
+
+ {/* Kolom Pertama */} +
+ {/* Dropdown untuk Application Name */} +
+ +
+ + {/* Dropdown untuk Expiry Time */} +
+ +
+ + {/* Dropdown untuk Template Name */} +
+ +
+
+ + {/* Kolom Kedua */} +
+ {/* Input untuk OTP Location */} +
+ +
+ + {/* Input untuk OTP Length */} +
+ +
+ + {/* Input untuk Template Review */} +
+ +
+
+
+ + {/* Tombol Save */} + +
+ ); +}; + +export default Authentication; + +// Definisi semua gaya +const styles = { + container: { + padding: "20px", + fontFamily: "Arial, sans-serif", + }, + row: { + display: "flex", + flexWrap: "wrap", + gap: "20px", + }, + column: { + flex: "1 1 calc(50% - 10px)", + minWidth: "300px", + }, + formGroup: { + marginBottom: "20px", + }, + input: { + width: "100%", + padding: "10px", + fontSize: "16px", + borderRadius: "4px", + border: "1px solid #ccc", + height: "40px", + boxSizing: "border-box", + }, + select: { + width: "100%", + padding: "10px", + fontSize: "16px", + borderRadius: "4px", + border: "1px solid #ccc", + height: "40px", + boxSizing: "border-box", + }, + button: { + padding: "10px 20px", + fontSize: "16px", + color: "#fff", + backgroundColor: "#1a73e8", + border: "none", + borderRadius: "4px", + cursor: "pointer", + marginTop: "20px", + }, +}; \ No newline at end of file diff --git a/src/screens/Wa/Activity/Section/Conversation.jsx b/src/screens/Wa/Activity/Section/Conversation.jsx new file mode 100644 index 0000000..5e2647a --- /dev/null +++ b/src/screens/Wa/Activity/Section/Conversation.jsx @@ -0,0 +1,242 @@ +import React, { useState, useEffect } from 'react'; +import { + Extract, + Quality, + AsyncIcon, + QualityAsync, + Transaction as TransactionIcon, +} from '../../../../assets/icon'; + +const Conversation = () => { + const [startDate, setStartDate] = useState(''); + const [endDate, setEndDate] = useState(''); + const [application, setApplication] = useState(''); + const [isMobile, setIsMobile] = useState(false); + + const menuData = [ + { id: 1, value: '150', label: 'Total Transaction', icon: TransactionIcon }, + { id: 2, value: '4', label: 'Total Extract', icon: Extract }, + { id: 3, value: '65', label: 'Total Quality', icon: Quality }, + { id: 6, value: '900', label: 'Total Extract Async', icon: AsyncIcon }, + { id: 4, value: '22', label: 'Total Quality Async', icon: QualityAsync }, + ]; + + const handleApply = () => { + console.log({ startDate, endDate, application }); + }; + + const handleCancel = () => { + setStartDate(''); + setEndDate(''); + setApplication(''); + }; + + // Detect if the device is mobile based on window width + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth <= 768); // Define mobile screen as width <= 768px + }; + + // Initialize on component mount + handleResize(); + + // Add event listener to update state on resize + window.addEventListener('resize', handleResize); + + // Cleanup event listener on component unmount + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + return ( +
+
+ {/* Row 1: Start Date and End Date */} +
+ setStartDate(e.target.value)} + style={styles.filterInput} + placeholder="Start Date" + /> + setEndDate(e.target.value)} + style={styles.filterInput} + placeholder="End Date" + /> +
+ + {/* Row 2: Application Select */} +
+ +
+ + {/* Row 3: Apply and Cancel Buttons */} +
+ + +
+
+ +
+ {menuData.map((item) => ( +
+
+

{item.value}

+

{item.label}

+
+
+ {item.label} +
+
+ ))} +
+
+ ); +}; + +const styles = { + container: { + margin: '3rem', + }, + filters: { + display: 'flex', + justifyContent: 'space-between', + marginBottom: '20px', + flexDirection: 'row', // Horizontal layout on desktop + gap: '10px', + }, + filtersMobile: { + display: 'flex', + flexDirection: 'column', // Vertical layout on mobile + gap: '15px', + }, + filterRow: { + display: 'flex', + justifyContent: 'space-between', + gap: '10px', + width: '100%', + }, + filterInput: { + padding: '10px', + border: '1px solid #ccc', + borderRadius: '5px', + fontSize: '16px', + width: '48%', // Adjust width to take up 48% of the row for input elements + }, + applyButton: { + backgroundColor: '#0542cc', + color: '#fff', + padding: '10px 20px', + border: 'none', + borderRadius: '5px', + cursor: 'pointer', + width: '48%', // Adjust button width to take half of the row + }, + cancelButton: { + backgroundColor: '#fff', + color: '#000', + padding: '10px 20px', + border: '1px solid gray', + borderRadius: '5px', + cursor: 'pointer', + width: '48%', // Adjust button width to take half of the row + }, + summaryCards: { + display: 'grid', + gridTemplateColumns: 'repeat(4, 1fr)', // 4 columns on desktop + gap: '20px', + marginTop: '20px', + }, + summaryCardsMobile: { + display: 'grid', + gridTemplateColumns: '1fr', // 1 column on mobile (full width) + gap: '15px', + marginTop: '20px', + }, + card: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + padding: '15px', // Reduced padding for a more compact card + backgroundColor: 'white', + borderRadius: '8px', // Slightly smaller border-radius for a sharper look + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)', + textAlign: 'left', + minWidth: '200px', // Ensure minimum width for mobile responsiveness + maxWidth: '300px', // Limit the maximum width to prevent cards from becoming too wide + width: '100%', + transition: 'transform 0.3s ease', // Smooth transition for hover effects + }, + cardHover: { + transform: 'scale(1.05)', // Slight zoom on hover for interactivity + }, + iconContainer: { + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + }, + textContainer: { + display: 'flex', + flexDirection: 'column', + }, + icon: { + width: '36px', // Smaller icon size for a more compact card + height: '36px', // Matching height for the icon + }, + cardTitle: { + fontSize: '18px', // Smaller font size for title to prevent overflow + margin: '0', + fontWeight: 'bold', + }, + cardText: { + fontSize: '12px', // Smaller text size for description to keep it balanced + color: '#555', + }, + + // Optional: Hover effect for the cards to enhance interactivity + cardHover: { + transform: 'scale(1.05)', // Slight zoom effect when hovering over card + }, + + // Media query for smaller screens (e.g., phones in portrait mode) + "@media (max-width: 768px)": { + summaryCards: { + gridTemplateColumns: '1fr', // 1 column on mobile screens + }, + card: { + padding: '10px', // Smaller padding for smaller screens + minWidth: '180px', // Adjust min width for mobile devices + maxWidth: '250px', // Adjust max width for mobile devices + }, + icon: { + width: '30px', // Slightly smaller icon size for mobile + height: '30px', // Matching height for mobile icon + }, + cardTitle: { + fontSize: '16px', // Smaller font size for the card title + }, + cardText: { + fontSize: '10px', // Smaller font size for card description + }, + }, +}; + +export default Conversation; diff --git a/src/screens/Wa/Activity/Section/Message.jsx b/src/screens/Wa/Activity/Section/Message.jsx new file mode 100644 index 0000000..4ef4d87 --- /dev/null +++ b/src/screens/Wa/Activity/Section/Message.jsx @@ -0,0 +1,93 @@ +import React from "react"; + +const Message = () => { + + return ( +
+
+ {/* Kolom Pertama */} +
+ {/* Dropdown untuk Application Name */} +
+ +
+ + {/* Dropdown untuk Template Name */} +
+ +
+ + {/* Input untuk Template Review */} +
+ +
+
+
+ + {/* Tombol Save */} + +
+ ); +}; + +export default Message; + +const styles = { + container: { + padding: "20px", + fontFamily: "Arial, sans-serif", + }, + row: { + display: "flex", + flexWrap: "wrap", + gap: "20px", + }, + column: { + flex: "1 1 calc(50% - 10px)", + minWidth: "300px", + }, + formGroup: { + marginBottom: "20px", + }, + input: { + width: "100%", + padding: "10px", + fontSize: "16px", + borderRadius: "4px", + border: "1px solid #ccc", + height: "40px", + boxSizing: "border-box", + }, + select: { + width: "100%", + padding: "10px", + fontSize: "16px", + borderRadius: "4px", + border: "1px solid #ccc", + height: "40px", + boxSizing: "border-box", + }, + button: { + padding: "10px 20px", + fontSize: "16px", + color: "#fff", + backgroundColor: "#1a73e8", + border: "none", + borderRadius: "4px", + cursor: "pointer", + marginTop: "20px", + }, +}; diff --git a/src/screens/Wa/Activity/Section/MessageLogs.jsx b/src/screens/Wa/Activity/Section/MessageLogs.jsx new file mode 100644 index 0000000..5cc32ab --- /dev/null +++ b/src/screens/Wa/Activity/Section/MessageLogs.jsx @@ -0,0 +1,811 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { FaChevronLeft, FaChevronRight, FaFastBackward, FaFastForward, FaSort, FaSortUp, FaSortDown } from 'react-icons/fa'; // Icons for sorting +import { NoAvailable } from '../../../../assets/icon'; + +const Pagination = ({ currentPage, totalPages, onPageChange }) => { + const handlePrev = () => { + if (currentPage > 1) { + onPageChange(currentPage - 1); + } + }; + + const handleNext = () => { + if (currentPage < totalPages) { + onPageChange(currentPage + 1); + } + }; + + const handleFirst = () => { + onPageChange(1); // Go to first page + }; + + const handleLast = () => { + onPageChange(totalPages); // Go to last page + }; + + // Logic to display only 3 pages in pagination + const getPaginationRange = () => { + const range = []; + const totalPagesCount = totalPages; + + let start = currentPage - 1; + let end = currentPage + 1; + + // Adjust start and end if near the boundaries + if (currentPage === 1) { + start = 1; + end = Math.min(3, totalPagesCount); + } else if (currentPage === totalPages) { + start = Math.max(totalPagesCount - 2, 1); + end = totalPagesCount; + } + + for (let i = start; i <= end; i++) { + range.push(i); + } + + return range; + }; + + const pageRange = getPaginationRange(); + + return ( +
+ {/* First Page Button */} + + + + + {/* Page Numbers */} + {pageRange.map((pageNum) => ( + + ))} + + + + {/* Last Page Button */} + +
+ ); +}; + +const SingleMessage = () => { + const [currentPage, setCurrentPage] = useState(1); + const [isMobile, setIsMobile] = useState(false); // State to detect mobile view + const [transactionData, setTransactionData] = useState([]); + const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); // Sorting state + const dataPerPage = 10; // Data per page (10 data per page) + + const buttonData = [ + { label: 'Copy', enabled: true }, + { label: 'CSV', enabled: true }, + { label: 'Excel', enabled: true }, + { label: 'PDF', enabled: true }, + { label: 'Print', enabled: true }, + { label: 'Column Visibility', enabled: true }, + ]; + + + // Generate 691 dummy transactions + const generateDummyData = (numOfItems) => { + const transactionData = []; + + for (let i = 1; i <= numOfItems; i++) { + transactionData.push({ + transactionId: `TX${String(i).padStart(3, '0')}`, // Transaction ID + applicationName: `App ${Math.floor(Math.random() * 5) + 1}`, // Application Name + templateName: `Template ${Math.floor(Math.random() * 10) + 1}`, // Random Template Name + language: ['English', 'Indonesian', 'Spanish', 'French'][Math.floor(Math.random() * 4)], // Random Language + category: ['Marketing', 'Transaction', 'Alert', 'Notification'][Math.floor(Math.random() * 4)], // Random Category + dateSent: new Date(2023, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1).toLocaleDateString(), // Random Date + destinationNumber: `+62${Math.floor(Math.random() * 900000000) + 800000000}`, // Random Destination Number + mode: Math.random() > 0.5 ? 'Online' : 'Offline', // Random Mode + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], // Random Status + }); + } + + + return transactionData; + }; + + + // Set the generated transaction data + useEffect(() => { + setTransactionData(generateDummyData(31)); // count data dummy transactions + }, []); + + // Sorting function + const sortData = (data, config) => { + const { key, direction } = config; + return [...data].sort((a, b) => { + if (a[key] < b[key]) { + return direction === 'asc' ? -1 : 1; + } + if (a[key] > b[key]) { + return direction === 'asc' ? 1 : -1; + } + return 0; + }); + }; + + // Handle column header sort click + const handleSort = (key) => { + let direction = 'asc'; + if (sortConfig.key === key && sortConfig.direction === 'asc') { + direction = 'desc'; // Toggle direction if the same column is clicked + } + setSortConfig({ key, direction }); + }; + + // Get the paginated data + const getPaginatedData = (data, page, perPage) => { + const sortedData = sortData(data, sortConfig); + const startIndex = (page - 1) * perPage; + const endIndex = startIndex + perPage; + return sortedData.slice(startIndex, endIndex); + }; + + // Handle page change + const handlePageChange = (page) => { + setCurrentPage(page); + }; + + // Calculate total pages based on the data and data per page + const totalPages = Math.ceil(transactionData.length / dataPerPage); + + // Paginated data + const paginatedData = getPaginatedData(transactionData, currentPage, dataPerPage); + + // Detect screen size and update isMobile state + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth <= 768); // Change 768 to your breakpoint + }; + + handleResize(); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + return ( +
+ {/* Filter Form */} +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + {/* Action Buttons */} +
+
+ {buttonData.map((button, index) => + button.enabled ? ( + + ) : null + )} +
+ + {/* Search Bar with Icon */} +
+ + + {/* FontAwesome search icon */} + +
+
+ + {/* Table */} +
+ + + + {/* Kolom untuk Nomor Urut */} + + + + + + + + + + + + + + {paginatedData.length > 0 ? ( + paginatedData.map((transaction, index) => ( + + {/* Kolom Nomor Urut */} + + + + + + + + + + + + )) + ) : ( + + + + )} + +
No. + + + + + + + + + + + + + + + + + +
{(currentPage - 1) * dataPerPage + index + 1}{transaction.transactionId}{transaction.applicationName}{transaction.templateName}{transaction.language}{transaction.category}{transaction.dateSent}{transaction.destinationNumber}{transaction.mode}{transaction.status}
+
+ No Data Available +

Data not available

+
+
+
+ + {/* Pagination */} + +
+ ); +}; + +const BulkMessage = () => { + const [currentPage, setCurrentPage] = useState(1); + const [isMobile, setIsMobile] = useState(false); // State to detect mobile view + const [transactionData, setTransactionData] = useState([]); + const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); // Sorting state + const dataPerPage = 10; // Data per page (10 data per page) + + const buttonData = [ + { label: 'Copy', enabled: true }, + { label: 'CSV', enabled: true }, + { label: 'Excel', enabled: true }, + { label: 'PDF', enabled: true }, + { label: 'Print', enabled: true }, + { label: 'Column Visibility', enabled: true }, + ]; + + + // Generate 691 dummy transactions + const generateDummyData = (numOfItems) => { + const transactionData = []; + + for (let i = 1; i <= numOfItems; i++) { + transactionData.push({ + transactionId: `TX${String(i).padStart(3, '0')}`, // Transaction ID + applicationName: `App ${Math.floor(Math.random() * 5) + 1}`, // Application Name + templateName: `Template ${Math.floor(Math.random() * 10) + 1}`, // Random Template Name + language: ['English', 'Indonesian', 'Spanish', 'French'][Math.floor(Math.random() * 4)], // Random Language + category: ['Marketing', 'Transaction', 'Alert', 'Notification'][Math.floor(Math.random() * 4)], // Random Category + dateSent: new Date(2023, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1).toLocaleDateString(), // Random Date + destinationNumber: `+62${Math.floor(Math.random() * 900000000) + 800000000}`, // Random Destination Number + mode: Math.random() > 0.5 ? 'Online' : 'Offline', // Random Mode + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], // Random Status + }); + } + + + return transactionData; + }; + + + // Set the generated transaction data + useEffect(() => { + setTransactionData(generateDummyData(31)); // count data dummy transactions + }, []); + + // Sorting function + const sortData = (data, config) => { + const { key, direction } = config; + return [...data].sort((a, b) => { + if (a[key] < b[key]) { + return direction === 'asc' ? -1 : 1; + } + if (a[key] > b[key]) { + return direction === 'asc' ? 1 : -1; + } + return 0; + }); + }; + + // Handle column header sort click + const handleSort = (key) => { + let direction = 'asc'; + if (sortConfig.key === key && sortConfig.direction === 'asc') { + direction = 'desc'; // Toggle direction if the same column is clicked + } + setSortConfig({ key, direction }); + }; + + // Get the paginated data + const getPaginatedData = (data, page, perPage) => { + const sortedData = sortData(data, sortConfig); + const startIndex = (page - 1) * perPage; + const endIndex = startIndex + perPage; + return sortedData.slice(startIndex, endIndex); + }; + + // Handle page change + const handlePageChange = (page) => { + setCurrentPage(page); + }; + + // Calculate total pages based on the data and data per page + const totalPages = Math.ceil(transactionData.length / dataPerPage); + + // Paginated data + const paginatedData = getPaginatedData(transactionData, currentPage, dataPerPage); + + // Detect screen size and update isMobile state + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth <= 768); // Change 768 to your breakpoint + }; + + handleResize(); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + return ( +
+ {/* Filter Form */} +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + {/* Action Buttons */} +
+
+ {buttonData.map((button, index) => + button.enabled ? ( + + ) : null + )} +
+ + {/* Search Bar with Icon */} +
+ + + {/* FontAwesome search icon */} + +
+
+ + {/* Table */} +
+ + + + {/* Kolom untuk Nomor Urut */} + + + + + + + + + + + + + + {paginatedData.length > 0 ? ( + paginatedData.map((transaction, index) => ( + + {/* Kolom Nomor Urut */} + + + + + + + + + + + + )) + ) : ( + + + + )} + +
No. + + + + + + + + + + + + + + + + + +
{(currentPage - 1) * dataPerPage + index + 1}{transaction.transactionId}{transaction.applicationName}{transaction.templateName}{transaction.language}{transaction.category}{transaction.dateSent}{transaction.destinationNumber}{transaction.mode}{transaction.status}
+
+ No Data Available +

Data not available

+
+
+
+ + {/* Pagination */} + +
+ ); +}; + +const MessageLogs = () => { + const [isSelectOpen, setIsSelectOpen] = useState(false); + const [activeTab, setActiveTab] = useState('single'); + const fileInputRef = useRef(null); + + const handleFocus = () => { + setIsSelectOpen(true); + }; + + const handleBlur = () => { + setIsSelectOpen(false); + }; + + const handleClick = async () => { + console.log('Make SMS Demo'); + }; + + const handleImageUpload = (event) => { + const file = event.target.files[0]; + if (file && (file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg')) { + console.log('File uploaded:', file.name); // Handle the file upload + } else { + alert('Please upload a valid image file (JPG, JPEG).'); + } + }; + + return ( +
+ {/* Tab buttons */} +
+ + +
+ + {/* Conditional content based on active tab */} + {activeTab === 'single' && } + {activeTab === 'bulk' && } +
+ ); +}; + + +export default MessageLogs; + +const styles = { + tabButton: { + display: 'inline-block', + padding: '10px 20px', + fontSize: '16px', + cursor: 'pointer', + backgroundColor: '#0542cc', + color: '#fff', + border: 'none', + marginRight: '10px', + borderRadius: '7px', + marginBottom: '12px' + }, + tabInactiveButton: { + display: 'inline-block', + padding: '10px 20px', + fontSize: '16px', + cursor: 'pointer', + backgroundColor: '#fff', + color: '#0542cc', + border: '1px solid #0542cc', + marginRight: '10px', + borderRadius: '7px', + marginBottom: '12px' + }, + tableContainer: { + minHeight: '300px', + maxHeight: '1500px', + overflowY: 'auto', + }, + iconStyle: { + width: '50px', + height: '50px', + }, + // Add margin-left style for icons + iconMarginLeft: { + marginLeft: '0.5rem', + verticalAlign: 'middle', + }, + buttonStyle: { + display: 'inline-flex', + justifyContent: 'flex-start', + alignItems: 'center', + padding: '0.5rem 1rem', + }, + actionButton: { + borderColor: '#000', + border: '1px solid black', + margin: '0 8px 8px 0', + padding: '8px 16px', + } +}; diff --git a/src/screens/Wa/Activity/Section/Transaction.jsx b/src/screens/Wa/Activity/Section/Transaction.jsx new file mode 100644 index 0000000..27f269b --- /dev/null +++ b/src/screens/Wa/Activity/Section/Transaction.jsx @@ -0,0 +1,242 @@ +import React, { useState, useEffect } from 'react'; +import { + Extract, + Quality, + AsyncIcon, + QualityAsync, + Transaction as TransactionIcon, +} from '../../../../assets/icon'; + +const Transaction = () => { + const [startDate, setStartDate] = useState(''); + const [endDate, setEndDate] = useState(''); + const [application, setApplication] = useState(''); + const [isMobile, setIsMobile] = useState(false); + + const menuData = [ + { id: 1, value: '150', label: 'Total Transaction', icon: TransactionIcon }, + { id: 2, value: '4', label: 'Total Extract', icon: Extract }, + { id: 3, value: '65', label: 'Total Quality', icon: Quality }, + { id: 6, value: '900', label: 'Total Extract Async', icon: AsyncIcon }, + { id: 4, value: '22', label: 'Total Quality Async', icon: QualityAsync }, + ]; + + const handleApply = () => { + console.log({ startDate, endDate, application }); + }; + + const handleCancel = () => { + setStartDate(''); + setEndDate(''); + setApplication(''); + }; + + // Detect if the device is mobile based on window width + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth <= 768); // Define mobile screen as width <= 768px + }; + + // Initialize on component mount + handleResize(); + + // Add event listener to update state on resize + window.addEventListener('resize', handleResize); + + // Cleanup event listener on component unmount + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + return ( +
+
+ {/* Row 1: Start Date and End Date */} +
+ setStartDate(e.target.value)} + style={styles.filterInput} + placeholder="Start Date" + /> + setEndDate(e.target.value)} + style={styles.filterInput} + placeholder="End Date" + /> +
+ + {/* Row 2: Application Select */} +
+ +
+ + {/* Row 3: Apply and Cancel Buttons */} +
+ + +
+
+ +
+ {menuData.map((item) => ( +
+
+

{item.value}

+

{item.label}

+
+
+ {item.label} +
+
+ ))} +
+
+ ); +}; + +const styles = { + container: { + margin: '3rem', + }, + filters: { + display: 'flex', + justifyContent: 'space-between', + marginBottom: '20px', + flexDirection: 'row', // Horizontal layout on desktop + gap: '10px', + }, + filtersMobile: { + display: 'flex', + flexDirection: 'column', // Vertical layout on mobile + gap: '15px', + }, + filterRow: { + display: 'flex', + justifyContent: 'space-between', + gap: '10px', + width: '100%', + }, + filterInput: { + padding: '10px', + border: '1px solid #ccc', + borderRadius: '5px', + fontSize: '16px', + width: '48%', // Adjust width to take up 48% of the row for input elements + }, + applyButton: { + backgroundColor: '#0542cc', + color: '#fff', + padding: '10px 20px', + border: 'none', + borderRadius: '5px', + cursor: 'pointer', + width: '48%', // Adjust button width to take half of the row + }, + cancelButton: { + backgroundColor: '#fff', + color: '#000', + padding: '10px 20px', + border: '1px solid gray', + borderRadius: '5px', + cursor: 'pointer', + width: '48%', // Adjust button width to take half of the row + }, + summaryCards: { + display: 'grid', + gridTemplateColumns: 'repeat(4, 1fr)', // 4 columns on desktop + gap: '20px', + marginTop: '20px', + }, + summaryCardsMobile: { + display: 'grid', + gridTemplateColumns: '1fr', // 1 column on mobile (full width) + gap: '15px', + marginTop: '20px', + }, + card: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + padding: '15px', // Reduced padding for a more compact card + backgroundColor: 'white', + borderRadius: '8px', // Slightly smaller border-radius for a sharper look + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)', + textAlign: 'left', + minWidth: '200px', // Ensure minimum width for mobile responsiveness + maxWidth: '300px', // Limit the maximum width to prevent cards from becoming too wide + width: '100%', + transition: 'transform 0.3s ease', // Smooth transition for hover effects + }, + cardHover: { + transform: 'scale(1.05)', // Slight zoom on hover for interactivity + }, + iconContainer: { + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + }, + textContainer: { + display: 'flex', + flexDirection: 'column', + }, + icon: { + width: '36px', // Smaller icon size for a more compact card + height: '36px', // Matching height for the icon + }, + cardTitle: { + fontSize: '18px', // Smaller font size for title to prevent overflow + margin: '0', + fontWeight: 'bold', + }, + cardText: { + fontSize: '12px', // Smaller text size for description to keep it balanced + color: '#555', + }, + + // Optional: Hover effect for the cards to enhance interactivity + cardHover: { + transform: 'scale(1.05)', // Slight zoom effect when hovering over card + }, + + // Media query for smaller screens (e.g., phones in portrait mode) + "@media (max-width: 768px)": { + summaryCards: { + gridTemplateColumns: '1fr', // 1 column on mobile screens + }, + card: { + padding: '10px', // Smaller padding for smaller screens + minWidth: '180px', // Adjust min width for mobile devices + maxWidth: '250px', // Adjust max width for mobile devices + }, + icon: { + width: '30px', // Slightly smaller icon size for mobile + height: '30px', // Matching height for mobile icon + }, + cardTitle: { + fontSize: '16px', // Smaller font size for the card title + }, + cardText: { + fontSize: '10px', // Smaller font size for card description + }, + }, +}; + +export default Transaction; diff --git a/src/screens/Wa/Activity/Section/index.js b/src/screens/Wa/Activity/Section/index.js new file mode 100644 index 0000000..bb12531 --- /dev/null +++ b/src/screens/Wa/Activity/Section/index.js @@ -0,0 +1,17 @@ +import Authentication from './Authentication'; +import Message from './Message'; +import Transaction from './Transaction'; +import Announcement from './Announcement'; +import Conversation from './Conversation'; +import AuthLogs from './AuthLogs'; +import MessageLogs from './MessageLogs'; + +export { + Authentication, + Message, + Transaction, + Announcement, + Conversation, + AuthLogs, + MessageLogs +} \ No newline at end of file diff --git a/src/screens/Wa/Activity/Settings.jsx b/src/screens/Wa/Activity/Settings.jsx new file mode 100644 index 0000000..fa2a0ee --- /dev/null +++ b/src/screens/Wa/Activity/Settings.jsx @@ -0,0 +1,130 @@ +import React, { useState, useEffect } from 'react'; +import { useLocation, useNavigate, Link, Routes, Route } from 'react-router-dom'; +import { + Authentication, + Message +} from './Section'; + +const Breadcrumb = ({ path }) => { + const location = useLocation(); + return ( + + ); +}; + +const Settings = () => { + const [isMobile, setIsMobile] = useState(window.innerWidth <= 768); + const navigate = useNavigate(); + + useEffect(() => { + if (window.location.pathname === '/wa-settings') { + navigate('wa-settings-auth', { replace: true }); + } + }, [navigate]); + + useEffect(() => { + const handleResize = () => setIsMobile(window.innerWidth <= 768); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + const breadcrumbPath = [ + { name: 'Activity', link: '/wa-settings' }, + { name: 'Setting', link: '/wa-settings' }, + ]; + + const settingsTabs = [ + { name: 'Authentication', link: 'wa-settings-auth' }, + { name: 'Message', link: 'wa-settings-message' } + ]; + + + return ( +
+
+ +
+
+ {settingsTabs.map((tab) => ( + + {tab.name} + + ))} +
+
+ + {/* Dynamic Tab Content */} +
+ + } /> + } /> + +
+
+
+ ); +}; + +export default Settings; + +const styles = { + container: { + padding: '1rem', + width: '100%', + margin: '0 auto', + boxSizing: 'border-box', + }, + wrapper: { + display: 'flex', + flexDirection: 'column', + border: '1px solid #ddd', + borderRadius: '8px', + padding: '1.5rem', + boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)', + backgroundColor: '#fff', + maxWidth: '1200px', + margin: '0 auto', + borderLeft: '5px solid #0542cc', + }, + wrapperMobile: { + display: 'flex', + flexDirection: 'column', + border: '1px solid #ddd', + borderRadius: '8px', + padding: '1rem', + boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)', + backgroundColor: '#fff', + borderLeft: '5px solid #0542cc', + }, + breadcrumb: { + marginBottom: '1rem', + fontSize: '0.9rem', + }, + breadcrumbLink: { + textDecoration: 'none', + color: '#0542cc', + }, + tabLink: { + padding: '10px 20px', + }, +}; diff --git a/src/screens/Wa/Activity/Summary.jsx b/src/screens/Wa/Activity/Summary.jsx new file mode 100644 index 0000000..a4b6c63 --- /dev/null +++ b/src/screens/Wa/Activity/Summary.jsx @@ -0,0 +1,105 @@ +import React, { useState, useEffect } from 'react'; +import { useLocation, useNavigate, Link, Routes, Route } from 'react-router-dom'; +import { + Transaction, + Announcement, + Conversation +} from './Section'; + +const Summary = () => { + const [isMobile, setIsMobile] = useState(window.innerWidth <= 768); + const navigate = useNavigate(); + + useEffect(() => { + if (window.location.pathname === '/wa-summary') { + navigate('wa-summary-transaction', { replace: true }); + } + }, [navigate]); + + useEffect(() => { + const handleResize = () => setIsMobile(window.innerWidth <= 768); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + const settingsTabs = [ + { name: 'Transaction', link: 'wa-summary-transaction' }, + { name: 'Announcement', link: 'wa-summary-announcement' }, + { name: 'Conversation Reports', link: 'wa-summary-conversation' } + ]; + + + return ( +
+
+
+
+ {settingsTabs.map((tab) => ( + + {tab.name} + + ))} +
+
+ + {/* Dynamic Tab Content */} +
+ + } /> + } /> + } /> + +
+
+
+ ); +}; + +export default Summary; + +const styles = { + container: { + padding: '1rem', + width: '100%', + margin: '0 auto', + boxSizing: 'border-box', + }, + wrapper: { + display: 'flex', + flexDirection: 'column', + border: '1px solid #ddd', + borderRadius: '8px', + padding: '1.5rem', + boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)', + backgroundColor: '#fff', + maxWidth: '1200px', + margin: '0 auto', + borderLeft: '5px solid #0542cc', + }, + wrapperMobile: { + display: 'flex', + flexDirection: 'column', + border: '1px solid #ddd', + borderRadius: '8px', + padding: '1rem', + boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)', + backgroundColor: '#fff', + borderLeft: '5px solid #0542cc', + }, + breadcrumb: { + marginBottom: '1rem', + fontSize: '0.9rem', + }, + breadcrumbLink: { + textDecoration: 'none', + color: '#0542cc', + }, + tabLink: { + padding: '10px 20px', + }, +}; diff --git a/src/screens/Wa/Activity/Transaction.jsx b/src/screens/Wa/Activity/Transaction.jsx new file mode 100644 index 0000000..65f0e86 --- /dev/null +++ b/src/screens/Wa/Activity/Transaction.jsx @@ -0,0 +1,102 @@ +import React, { useState, useEffect } from 'react'; +import { useLocation, useNavigate, Link, Routes, Route } from 'react-router-dom'; +import { + AuthLogs, + MessageLogs +} from './Section'; + +const Transaction = () => { + const [isMobile, setIsMobile] = useState(window.innerWidth <= 768); + const navigate = useNavigate(); + + useEffect(() => { + if (window.location.pathname === '/wa-transaction') { + navigate('wa-transaction-auth', { replace: true }); + } + }, [navigate]); + + useEffect(() => { + const handleResize = () => setIsMobile(window.innerWidth <= 768); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + const settingsTabs = [ + { name: 'Authentication', link: 'wa-transaction-auth' }, + { name: 'Message', link: 'wa-transaction-message' } + ]; + + + return ( +
+
+
+
+ {settingsTabs.map((tab) => ( + + {tab.name} + + ))} +
+
+ + {/* Dynamic Tab Content */} +
+ + } /> + } /> + +
+
+
+ ); +}; + +export default Transaction; + +const styles = { + container: { + padding: '1rem', + width: '100%', + margin: '0 auto', + boxSizing: 'border-box', + }, + wrapper: { + display: 'flex', + flexDirection: 'column', + border: '1px solid #ddd', + borderRadius: '8px', + padding: '1.5rem', + boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)', + backgroundColor: '#fff', + maxWidth: '1200px', + margin: '0 auto', + borderLeft: '5px solid #0542cc', + }, + wrapperMobile: { + display: 'flex', + flexDirection: 'column', + border: '1px solid #ddd', + borderRadius: '8px', + padding: '1rem', + boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)', + backgroundColor: '#fff', + borderLeft: '5px solid #0542cc', + }, + breadcrumb: { + marginBottom: '1rem', + fontSize: '0.9rem', + }, + breadcrumbLink: { + textDecoration: 'none', + color: '#0542cc', + }, + tabLink: { + padding: '10px 20px', + }, +}; diff --git a/src/screens/Wa/Activity/index.js b/src/screens/Wa/Activity/index.js new file mode 100644 index 0000000..8e0d256 --- /dev/null +++ b/src/screens/Wa/Activity/index.js @@ -0,0 +1,12 @@ +import Settings from './Settings'; +import Summary from './Summary'; +import Transaction from './Transaction'; +import Bulk from './Bulk'; + + +export { + Settings, + Summary, + Transaction, + Bulk +} diff --git a/src/screens/Wa/Block/Block.jsx b/src/screens/Wa/Block/Block.jsx new file mode 100644 index 0000000..896458b --- /dev/null +++ b/src/screens/Wa/Block/Block.jsx @@ -0,0 +1,460 @@ +import React, { useState, useEffect } from 'react'; +import { + FaChevronLeft, + FaChevronRight, + FaFastBackward, + FaFastForward, + FaSort, + FaSortUp, + FaSortDown, + FaEdit, + FaEye, + FaTrash +} from 'react-icons/fa'; // Icons for sorting +import { NoAvailable } from '../../../assets/icon'; +import { Link } from 'react-router-dom'; + +// Pagination Component +const Pagination = ({ currentPage, totalPages, onPageChange }) => { + const handlePrev = () => { + if (currentPage > 1) { + onPageChange(currentPage - 1); + } + }; + + const handleNext = () => { + if (currentPage < totalPages) { + onPageChange(currentPage + 1); + } + }; + + const handleFirst = () => { + onPageChange(1); // Go to first page + }; + + const handleLast = () => { + onPageChange(totalPages); // Go to last page + }; + + // Logic to display only 3 pages in pagination + const getPaginationRange = () => { + const range = []; + const totalPagesCount = totalPages; + + let start = currentPage - 1; + let end = currentPage + 1; + + // Adjust start and end if near the boundaries + if (currentPage === 1) { + start = 1; + end = Math.min(3, totalPagesCount); + } else if (currentPage === totalPages) { + start = Math.max(totalPagesCount - 2, 1); + end = totalPagesCount; + } + + for (let i = start; i <= end; i++) { + range.push(i); + } + + return range; + }; + + const pageRange = getPaginationRange(); + + return ( +
+ {/* First Page Button */} + + + + + {/* Page Numbers */} + {pageRange.map((pageNum) => ( + + ))} + + + + {/* Last Page Button */} + +
+ ); +}; + +const Block = () => { + const [currentPage, setCurrentPage] = useState(1); + const [isMobile, setIsMobile] = useState(false); // State to detect mobile view + const [transactionData, setTransactionData] = useState([]); + const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); // Sorting state + const dataPerPage = 10; // Data per page (10 data per page) + + const buttonData = [ + { label: 'Copy', enabled: true }, + { label: 'CSV', enabled: true }, + { label: 'Excel', enabled: true }, + { label: 'PDF', enabled: true }, + { label: 'Print', enabled: true }, + { label: 'Column Visibility', enabled: true }, + ]; + + + // Generate 691 dummy transactions + const generateDummyData = (numOfItems) => { + const transactionData = []; + + for (let i = 1; i <= numOfItems; i++) { + transactionData.push({ + transactionId: `TX${String(i).padStart(4, '0')}`, // Transaction ID (e.g., TX0001, TX0002, ...) + applicationName: `Application ${Math.floor(Math.random() * 5) + 1}`, // Random application name (e.g., Application 1, Application 2, ...) + phoneNumber: `+1${Math.floor(Math.random() * 1000000000)}`, // Random phone number (e.g., +1234567890) + description: `Description ${Math.floor(Math.random() * 100) + 1}`, // Random description (e.g., Description 1, Description 2, ...) + }); + } + + return transactionData; + }; + + + // Set the generated transaction data + useEffect(() => { + setTransactionData(generateDummyData(52)); // count data dummy transactions + }, []); + + // Sorting function + const sortData = (data, config) => { + const { key, direction } = config; + return [...data].sort((a, b) => { + if (a[key] < b[key]) { + return direction === 'asc' ? -1 : 1; + } + if (a[key] > b[key]) { + return direction === 'asc' ? 1 : -1; + } + return 0; + }); + }; + + // Handle column header sort click + const handleSort = (key) => { + let direction = 'asc'; + if (sortConfig.key === key && sortConfig.direction === 'asc') { + direction = 'desc'; // Toggle direction if the same column is clicked + } + setSortConfig({ key, direction }); + }; + + // Get the paginated data + const getPaginatedData = (data, page, perPage) => { + const sortedData = sortData(data, sortConfig); + const startIndex = (page - 1) * perPage; + const endIndex = startIndex + perPage; + return sortedData.slice(startIndex, endIndex); + }; + + // Handle page change + const handlePageChange = (page) => { + setCurrentPage(page); + }; + + // Calculate total pages based on the data and data per page + const totalPages = Math.ceil(transactionData.length / dataPerPage); + + // Paginated data + const paginatedData = getPaginatedData(transactionData, currentPage, dataPerPage); + + // Detect screen size and update isMobile state + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth <= 768); // Change 768 to your breakpoint + }; + + handleResize(); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + // Define your handle functions + const handleEdit = (transactionId) => { + console.log(`Edit transaction with ID: ${transactionId}`); + // Add your edit logic here + }; + + const handleShow = (transactionId) => { + console.log(`Show transaction with ID: ${transactionId}`); + // Add your show logic here + }; + + const handleDelete = (transactionId) => { + console.log(`Delete transaction with ID: ${transactionId}`); + // Add your delete logic here + }; + + return ( +
+ {/* Welcome Message */} +
+
+
+

+ Alert +

+

+ Get started now by creating an Application ID and explore all the demo services available on the dashboard. + Experience the ease and flexibility of trying out all our features firsthand. +

+
+
+
+ +
+ {/* Filter Form */} +
+
{/* Using Flexbox */} + + {/* Dropdown: Business Account */} +
+ +
+ + {/* Dropdown: Status */} +
+ +
+ + {/* Apply and Cancel Buttons */} +
+ + +
+ + {/* Create Settings Button with Icon */} +
+ + + +
+
+
+ + {/* Action Buttons */} +
+
+ {buttonData.map((button, index) => + button.enabled ? ( + + ) : null + )} +
+ + {/* Search Bar with Icon */} +
+ + + {/* FontAwesome search icon */} + +
+
+ + {/* Table */} +
+ + + + + + + + + + + + + + {paginatedData.length > 0 ? ( + paginatedData.map((transaction, index) => ( + + {/* Kolom Nomor Urut */} + {/* Nomor urut berdasarkan halaman dan index */} + + + + + + + )) + ) : ( + + + + )} + +
No. + + + + + + + + Action
{(currentPage - 1) * dataPerPage + index + 1}{transaction.transactionId}{transaction.applicationName}{transaction.phoneNumber}{transaction.description} +
+ + + + + +
+
+
+ No Data Available +

Data not available

+
+
+
+ + {/* Pagination */} + +
+
+ ); +}; + +export default Block; + +const styles = { + contentContainer: { + padding: '20px', + border: '0.1px solid rgba(0, 0, 0, 0.2)', + borderLeft: '4px solid #0542cc', + borderRadius: '10px', + width: '100%', + }, + tableContainer: { + minHeight: '300px', + maxHeight: '1500px', + overflowY: 'auto', + }, + iconStyle: { + width: '50px', + height: '50px', + }, + // Add margin-left style for icons + iconMarginLeft: { + marginLeft: '0.5rem', + verticalAlign: 'middle', + }, + buttonStyle: { + display: 'inline-flex', + justifyContent: 'flex-start', + alignItems: 'center', + padding: '0.5rem 1rem', + }, +}; + diff --git a/src/screens/Wa/Block/index.js b/src/screens/Wa/Block/index.js new file mode 100644 index 0000000..7142785 --- /dev/null +++ b/src/screens/Wa/Block/index.js @@ -0,0 +1,5 @@ +import Block from './Block'; + +export { + Block +} \ No newline at end of file diff --git a/src/screens/Wa/Inbox/Inbox.jsx b/src/screens/Wa/Inbox/Inbox.jsx new file mode 100644 index 0000000..128ae51 --- /dev/null +++ b/src/screens/Wa/Inbox/Inbox.jsx @@ -0,0 +1,107 @@ +import { height } from '@fortawesome/free-solid-svg-icons/fa0'; +import React from 'react'; + +const Inbox = () => { + return ( +
+
+
+ 💬 +

Activate Inbox

+
+

+ Inbox allows seamless two-way communication with your end-users. By activating this feature, you agree + to a processing fee for each message sent and received. +

+
+ + +
+
+ + +
+
+
+ ); +}; + +const styles = { + overlay: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + height: '100vh', + backgroundColor: 'rgba(0, 0, 0, 0.1)', + }, + modal: { + width: '43%', + height: '33%', + padding: '20px', + backgroundColor: '#fff', + borderRadius: '8px', + boxShadow: '0 4px 10px rgba(0, 0, 0, 0.2)', + textAlign: 'center', + borderLeft: '5px solid #0542cc', + }, + header: { + marginBottom: '16px', + }, + icon: { + fontSize: '2rem', + color: '#0542cc', + }, + title: { + margin: '8px 0 0', + fontSize: '1.5rem', + fontWeight: 'bold', + color: '#333', + }, + description: { + fontSize: '1rem', + color: '#555', + marginBottom: '20px', + }, + terms: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + marginBottom: '20px', + }, + checkbox: { + marginRight: '10px', + }, + label: { + fontSize: '0.9rem', + color: '#555', + }, + link: { + color: '#0542cc', + textDecoration: 'none', + }, + actions: { + display: 'flex', + justifyContent: 'space-between', + marginTop: '10px', + }, + cancelButton: { + padding: '10px 20px', + backgroundColor: '#fff', + border: '1px solid #ccc', + borderRadius: '4px', + color: '#555', + cursor: 'pointer', + }, + activateButton: { + padding: '10px 20px', + backgroundColor: '#0542cc', + color: '#fff', + border: 'none', + borderRadius: '4px', + cursor: 'pointer', + }, +}; + +export default Inbox; diff --git a/src/screens/Wa/Inbox/index.js b/src/screens/Wa/Inbox/index.js new file mode 100644 index 0000000..7a2031c --- /dev/null +++ b/src/screens/Wa/Inbox/index.js @@ -0,0 +1,5 @@ +import Inbox from "./Inbox"; + +export { + Inbox +} \ No newline at end of file diff --git a/src/screens/Wa/Manage/Content/CreateSettings.jsx b/src/screens/Wa/Manage/Content/CreateSettings.jsx index bb40d49..487f0a8 100644 --- a/src/screens/Wa/Manage/Content/CreateSettings.jsx +++ b/src/screens/Wa/Manage/Content/CreateSettings.jsx @@ -126,6 +126,7 @@ const styles = { backgroundColor: '#fff', maxWidth: '1200px', margin: '0 auto', + borderLeft: '5px solid #0542cc', }, wrapperMobile: { display: 'flex', @@ -135,6 +136,7 @@ const styles = { padding: '1rem', boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)', backgroundColor: '#fff', + borderLeft: '5px solid #0542cc', }, breadcrumb: { marginBottom: '1rem',