From 262dce053f552c038cb5729405b06fc836d9c8cf Mon Sep 17 00:00:00 2001 From: Vassshhh Date: Wed, 6 Aug 2025 18:28:52 +0700 Subject: [PATCH] ok --- src/FollowUps.js | 62 ++++++++++---- src/FollowUps.module.css | 171 ++++++++++++++++++++++++--------------- 2 files changed, 155 insertions(+), 78 deletions(-) diff --git a/src/FollowUps.js b/src/FollowUps.js index 6b6cf83..365d4dd 100644 --- a/src/FollowUps.js +++ b/src/FollowUps.js @@ -1,4 +1,3 @@ -// FollowUps.js import React, { useState } from 'react'; import styles from './FollowUps.module.css'; @@ -46,9 +45,38 @@ const FollowUps = ({ data: initialData }) => { } }; + // Gabungkan data berdasarkan contact_info + const mergedDataMap = new Map(); + + data.forEach(user => { + const key = user.contact_info; + + if (!mergedDataMap.has(key)) { + mergedDataMap.set(key, { + ...user, + notesList: [{ + note: user.notes, + created_at: user.created_at + }] + }); + } else { + const existing = mergedDataMap.get(key); + existing.notesList.push({ + note: user.notes, + created_at: user.created_at + }); + + // Prioritaskan status tertinggi + existing.issuccess = existing.issuccess || user.issuccess; + existing.isfollowup = existing.issuccess ? false : (existing.isfollowup || user.isfollowup); + } + }); + + const mergedData = Array.from(mergedDataMap.values()); + // Filter & Sort const now = new Date(); - const filteredData = data + const filteredData = mergedData .filter(user => { switch (statusFilter) { case 'pending': @@ -62,7 +90,8 @@ const FollowUps = ({ data: initialData }) => { } }) .filter(user => { - const created = new Date(user.created_at); + const latestNote = user.notesList[user.notesList.length - 1]; + const created = new Date(latestNote.created_at); switch (dateFilter) { case 'today': return created.toDateString() === now.toDateString(); @@ -75,9 +104,9 @@ const FollowUps = ({ data: initialData }) => { } }) .sort((a, b) => { - const dateA = new Date(a.created_at); - const dateB = new Date(b.created_at); - return sortOrder === 'latest' ? dateB - dateA : dateA - dateB; + const aDate = new Date(a.notesList[a.notesList.length - 1].created_at); + const bDate = new Date(b.notesList[b.notesList.length - 1].created_at); + return sortOrder === 'latest' ? bDate - aDate : aDate - bDate; }); return ( @@ -139,7 +168,7 @@ const FollowUps = ({ data: initialData }) => { ) : ( filteredData.map(user => ( -
+

{user.name}

@@ -154,18 +183,21 @@ const FollowUps = ({ data: initialData }) => {
-

{user.notes}

+
    + {user.notesList.map((entry, index) => ( +
  • + {new Date(entry.created_at).toLocaleString('id-ID', { + dateStyle: 'medium', + timeStyle: 'short', + timeZone: 'Asia/Jakarta' + })}: {entry.note} +
  • + ))} +
Contact: {user.contact_info}
-
- {new Date(user.created_at).toLocaleString('id-ID', { - dateStyle: 'medium', - timeStyle: 'short', - timeZone: 'Asia/Jakarta' - })} -
diff --git a/src/FollowUps.module.css b/src/FollowUps.module.css index 9c566c4..19958ef 100644 --- a/src/FollowUps.module.css +++ b/src/FollowUps.module.css @@ -1,6 +1,6 @@ /* FollowUps.module.css */ .container { - background-color: #f8fafc; + background-color: #f1f3f4; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; @@ -12,8 +12,8 @@ border-radius: 12px; padding: 20px; margin-bottom: 24px; - border: 1px solid #e2e8f0; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + border: 1px solid #e0e0e0; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); } .filterGroup { @@ -79,37 +79,38 @@ .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - gap: 20px; + gap: 16px; } .card { - background: white; + background: #f8f9fa; border-radius: 12px; - border: 1px solid #e2e8f0; + border: 1px solid #dee2e6; overflow: hidden; transition: all 0.2s ease; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); } .card:hover { - transform: translateY(-2px); - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); - border-color: #cbd5e1; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); + border-color: #adb5bd; } .cardHeader { - padding: 20px 20px 12px; - border-bottom: 1px solid #f1f5f9; + padding: 18px 18px 12px; + border-bottom: 1px solid #e9ecef; display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; + background: #ffffff; } .userName { - font-size: 18px; + font-size: 16px; font-weight: 600; - color: #1f2937; + color: #212529; margin: 0; flex: 1; } @@ -119,42 +120,71 @@ } .badgeSuccess { - background: #dcfce7; - color: #166534; + background: #d1e7dd; + color: #0a3622; padding: 4px 8px; - border-radius: 6px; - font-size: 12px; + border-radius: 4px; + font-size: 11px; font-weight: 500; + border: 1px solid #badbcc; } .badgeProgress { - background: #fef3c7; - color: #92400e; + background: #fff3cd; + color: #664d03; padding: 4px 8px; - border-radius: 6px; - font-size: 12px; + border-radius: 4px; + font-size: 11px; font-weight: 500; + border: 1px solid #ffda6a; } .badgePending { - background: #f3f4f6; - color: #6b7280; + background: #e2e3e5; + color: #41464b; padding: 4px 8px; - border-radius: 6px; - font-size: 12px; + border-radius: 4px; + font-size: 11px; font-weight: 500; + border: 1px solid #c4c8cc; } .cardContent { - padding: 12px 20px 20px; + padding: 16px 18px; + background: #f8f9fa; } -.notes { - color: #4b5563; - font-size: 14px; - line-height: 1.5; +.notesList { margin: 0 0 16px 0; - word-break: break-word; + padding: 12px; + list-style-type: none; + font-size: 14px; + color: #212529; + background-color: #ffffff; + border-radius: 6px; + border: 1px solid #e9ecef; + max-height: 120px; + overflow-y: auto; +} + +.notesList li { + margin-bottom: 8px; + padding: 6px 0; + border-bottom: 1px solid #f8f9fa; + line-height: 1.4; +} + +.notesList li:last-child { + margin-bottom: 0; + border-bottom: none; +} + +.notesList li strong { + color: #6c757d; + font-weight: 500; + font-size: 12px; + display: block; + margin-bottom: 2px; } .contactInfo { @@ -166,37 +196,33 @@ .contactLabel { font-size: 12px; - color: #6b7280; + color: #6c757d; font-weight: 500; } .contactValue { - font-size: 14px; - color: #374151; + font-size: 13px; + color: #495057; font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; -} - -.dateInfo { - font-size: 12px; - color: #9ca3af; - padding: 8px 12px; - background: #f9fafb; - border-radius: 6px; - border-left: 3px solid #e5e7eb; + background: #ffffff; + padding: 4px 6px; + border-radius: 4px; + border: 1px solid #e9ecef; + display: inline-block; } .cardActions { - padding: 16px 20px; - border-top: 1px solid #f1f5f9; - background: #fafbfc; + padding: 14px 18px; + border-top: 1px solid #e9ecef; + background: #ffffff; } .actionBtn { width: 100%; - padding: 12px 16px; + padding: 10px 16px; border: none; - border-radius: 8px; - font-size: 14px; + border-radius: 6px; + font-size: 13px; font-weight: 500; cursor: pointer; transition: all 0.2s ease; @@ -209,27 +235,32 @@ .btnPrimary { background: #25d366; color: white; + border: 1px solid #25d366; } .btnPrimary:hover { background: #1da851; transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(37, 211, 102, 0.3); } .btnComplete { - background: #3b82f6; + background: #0d6efd; color: white; + border: 1px solid #0d6efd; } .btnComplete:hover { - background: #2563eb; + background: #0b5ed7; transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(13, 110, 253, 0.3); } .btnSuccess { - background: #10b981; + background: #198754; color: white; cursor: default; + border: 1px solid #198754; } /* Empty State */ @@ -238,16 +269,21 @@ text-align: center; padding: 60px 20px; color: #6b7280; + background: #f8f9fa; + border-radius: 12px; + border: 1px solid #dee2e6; } .emptyIcon { font-size: 48px; margin-bottom: 16px; + opacity: 0.5; } .emptyState p { font-size: 16px; margin: 0; + color: #6c757d; } /* Responsive Design */ @@ -272,27 +308,31 @@ .grid { grid-template-columns: 1fr; - gap: 16px; + gap: 12px; } .cardHeader { - padding: 16px 16px 10px; + padding: 14px 14px 10px; flex-direction: column; align-items: flex-start; gap: 8px; } .cardContent { - padding: 10px 16px 16px; + padding: 12px 14px; } .cardActions { - padding: 12px 16px; + padding: 10px 14px; } .actionBtn { - padding: 10px 14px; - font-size: 13px; + padding: 9px 14px; + font-size: 12px; + } + + .userName { + font-size: 15px; } } @@ -301,16 +341,21 @@ padding: 12px; } - .userName { - font-size: 16px; + .grid { + gap: 10px; } - .notes { + .userName { + font-size: 14px; + } + + .notesList { font-size: 13px; + padding: 10px; } .statusBadge span { - font-size: 11px; + font-size: 10px; padding: 3px 6px; } } \ No newline at end of file