diff --git a/apps/frontend/src/app.tsx b/apps/frontend/src/app.tsx index d9b13f9..15c7131 100644 --- a/apps/frontend/src/app.tsx +++ b/apps/frontend/src/app.tsx @@ -18,7 +18,13 @@ import { DonorStatsChart } from '@components/DonorStatsChart'; import DashboardOverview from '@containers/dashboard/sidebar/DashboardOverview'; import { EmailEditor } from './components/EmailComms/EmailEditorOverviewPage'; import { AdminGrowingGoalTester } from '@containers/dashboard/AdminGrowingGoalTester'; +import ExportModalTester from '@components/DonationModals/ExportModalTester'; +import { DonationInformationModalTester } from '@components/DonationModals/DonationInformationModalTester'; +import { NewDonationModalTester } from '@components/DonationModals/NewDonationModalTester'; +import { SortingModalTester } from '@components/DonationModals/SortingModalTester'; import OverviewPage from '@containers/dashboard/OverviewPage'; +import EditDonationGoalTester from '@components/DonationGoal/EditDonationGoalTester'; +import Sidebar from '@containers/dashboard/sidebar/Sidebar'; const router = createBrowserRouter([ { @@ -67,6 +73,22 @@ const router = createBrowserRouter([ }, ], }, + { + path: '/sidebar-test', + element: , + }, + { + path: '/export-modal-test', + element: , + }, + { + path: '/donation-information-modal-test', + element: , + }, + { + path: '/edit-donation-goal-test', + element: , + }, { path: '/test', element: , @@ -79,6 +101,14 @@ const router = createBrowserRouter([ path: '/admin-growing-goal-test', element: , }, + { + path: '/new-donation-modal-test', + element: , + }, + { + path: '/sorting-modal-test', + element: , + }, { path: '/chart', element: , diff --git a/apps/frontend/src/components/DonationModals/DonationInformationModal.tsx b/apps/frontend/src/components/DonationModals/DonationInformationModal.tsx new file mode 100644 index 0000000..1eb9136 --- /dev/null +++ b/apps/frontend/src/components/DonationModals/DonationInformationModal.tsx @@ -0,0 +1,341 @@ +import { useState } from 'react'; +import { Calendar } from 'lucide-react'; + +interface RecurrenceOption { + id: string; + label: string; + left: string; + top: string; + checkLeft: string; + checkTop: string; +} + +const RECURRENCE_OPTIONS: RecurrenceOption[] = [ + { + id: 'one-time', + label: 'One-Time', + left: 'left-[20px]', + top: 'top-[128px]', + checkLeft: 'left-[29.03px]', + checkTop: 'top-[136px]', + }, + { + id: 'weekly', + label: 'Weekly', + left: 'left-[126px]', + top: 'top-[128px]', + checkLeft: 'left-[136.03px]', + checkTop: 'top-[136px]', + }, + { + id: 'monthly', + label: 'Monthly', + left: 'left-[20px]', + top: 'top-[165px]', + checkLeft: 'left-[29.03px]', + checkTop: 'top-[173px]', + }, + { + id: 'yearly', + label: 'Yearly', + left: 'left-[126px]', + top: 'top-[165px]', + checkLeft: 'left-[136.03px]', + checkTop: 'top-[173px]', + }, +]; + +const LABEL_POSITIONS: Record = { + 'one-time': { left: 'left-[49.23px]', top: 'top-[136px]' }, + weekly: { left: 'left-[157px]', top: 'top-[136px]' }, + monthly: { left: 'left-[49px]', top: 'top-[173px]' }, + yearly: { left: 'left-[157px]', top: 'top-[173px]' }, +}; + +const INITIAL_SELECTED = { + 'one-time': true, + weekly: true, + monthly: true, + yearly: true, +}; + +const INITIAL_RANGE: [number, number] = [0, 1000]; + +export const DonationInformationModal = () => { + const [selected, setSelected] = + useState>(INITIAL_SELECTED); + const [amountRange, setAmountRange] = + useState<[number, number]>(INITIAL_RANGE); + const [amountFrom, setAmountFrom] = useState(''); + const [amountTo, setAmountTo] = useState(''); + const [dateFrom, setDateFrom] = useState(''); + const [dateTo, setDateTo] = useState(''); + + const toggleOption = (id: string) => { + setSelected((prev) => ({ ...prev, [id]: !prev[id] })); + }; + + const handleReset = () => { + setSelected(INITIAL_SELECTED); + setAmountRange(INITIAL_RANGE); + setAmountFrom(''); + setAmountTo(''); + setDateFrom(''); + setDateTo(''); + }; + + const handleApply = () => { + // TODO: wire up apply logic + }; + + const handleMinChange = (e: React.ChangeEvent) => { + const value = Number(e.target.value); + if (value < amountRange[1]) { + setAmountRange([value, amountRange[1]]); + } + }; + + const handleMaxChange = (e: React.ChangeEvent) => { + const value = Number(e.target.value); + if (value > amountRange[0]) { + setAmountRange([amountRange[0], value]); + } + }; + + const formatDate = (value: string) => { + if (!value) return ''; + const [year, month, day] = value.split('-'); + return `${month}/${day}/${year}`; + }; + + const placeholderLabelClass = + "text-neutral-500 text-[10px] font-normal font-['Source_Sans_Pro'] leading-4"; + const blackLabelClass = + "text-black text-[10px] font-normal font-['Source_Sans_Pro'] leading-4"; + + const DateBox = ({ + label, + value, + onChange, + left, + }: { + label: string; + value: string; + onChange: (v: string) => void; + left: string; + }) => ( +
+
+ {label} +
+
+ +
+ + {value ? formatDate(value) : 'MM/DD/YYYY'} + + onChange(e.target.value)} + className="absolute inset-0 w-full h-full opacity-0 cursor-pointer" + /> +
+
+
+ ); + + return ( +
+ {/* Date Label */} +
+ Date +
+ + + + + {/* Recurrence Label */} +
+ Recurrence +
+ + {/* Recurrence Checkboxes */} + {RECURRENCE_OPTIONS.map((option) => ( +
toggleOption(option.id)} + className="cursor-pointer" + > +
+
+ {selected[option.id] && ( + + + + )} +
+
+ {option.label} +
+
+ ))} + + {/* Amount Label */} +
+ Amount +
+ + {/* Slider Track */} +
+ + {/* Slider Min */} + + + {/* Slider Max */} + + {/* Min Label */} +
+ Min +
+ + {/* Max Label */} +
+ Max +
+ + {/* Amount From Box */} +
+
From
+ setAmountFrom(e.target.value)} + className={`w-full bg-transparent border-none outline-none ${blackLabelClass}`} + /> +
+ + {/* Amount To Box */} +
+
To
+ setAmountTo(e.target.value)} + className={`w-full bg-transparent border-none outline-none ${blackLabelClass}`} + /> +
+ + {/* Reset Button */} + + + {/* Apply Button */} + +
+ ); +}; diff --git a/apps/frontend/src/components/DonationModals/DonationInformationModalTester.tsx b/apps/frontend/src/components/DonationModals/DonationInformationModalTester.tsx new file mode 100644 index 0000000..c87b599 --- /dev/null +++ b/apps/frontend/src/components/DonationModals/DonationInformationModalTester.tsx @@ -0,0 +1,9 @@ +import { DonationInformationModal } from './DonationInformationModal'; + +export const DonationInformationModalTester = () => { + return ( +
+ +
+ ); +}; diff --git a/apps/frontend/src/components/DonationModals/ExportModal.tsx b/apps/frontend/src/components/DonationModals/ExportModal.tsx new file mode 100644 index 0000000..67936e5 --- /dev/null +++ b/apps/frontend/src/components/DonationModals/ExportModal.tsx @@ -0,0 +1,29 @@ +type ExportModalProps = { + onExportCsv?: () => void; + onExportPdf?: () => void; +}; + +export default function ExportModal({ + onExportCsv, + onExportPdf, +}: ExportModalProps) { + return ( +
+ + + +
+ ); +} diff --git a/apps/frontend/src/components/DonationModals/ExportModalTester.tsx b/apps/frontend/src/components/DonationModals/ExportModalTester.tsx new file mode 100644 index 0000000..a7ca94d --- /dev/null +++ b/apps/frontend/src/components/DonationModals/ExportModalTester.tsx @@ -0,0 +1,20 @@ +import ExportModal from './ExportModal'; + +export default function ExportModalTester() { + return ( +
+
+

ExportModal tester

+ + { + console.log('Export as CSV clicked'); + }} + onExportPdf={() => { + console.log('Export as PDF clicked'); + }} + /> +
+
+ ); +} diff --git a/apps/frontend/src/components/DonationModals/NewDonationModal.tsx b/apps/frontend/src/components/DonationModals/NewDonationModal.tsx new file mode 100644 index 0000000..d2d92c9 --- /dev/null +++ b/apps/frontend/src/components/DonationModals/NewDonationModal.tsx @@ -0,0 +1,172 @@ +import { useState } from 'react'; +import { Calendar } from 'lucide-react'; + +export const NewDonationModal = () => { + const [firstName, setFirstName] = useState(''); + const [lastName, setLastName] = useState(''); + const [email, setEmail] = useState(''); + const [amount, setAmount] = useState(''); + const [date, setDate] = useState(''); + const [reason, setReason] = useState(''); + + const handleCancel = () => { + setFirstName(''); + setLastName(''); + setEmail(''); + setAmount(''); + setDate(''); + setReason(''); + //might hsve to change this logic + }; + + const handleAdd = () => { + // TODO: wire up add logic + }; + + const labelClass = + "justify-start text-neutral-700 text-xl font-semibold font-['Source_Sans_Pro']"; + const inputClass = + "w-full bg-transparent border-none outline-none text-neutral-500 text-xl font-normal font-['Source_Sans_Pro'] placeholder:text-neutral-500"; + const boxClass = + 'absolute px-5 pt-2 pb-3 bg-white rounded-[10px] outline outline-1 outline-offset-[-1px] outline-neutral-500 inline-flex justify-start items-center'; + + return ( +
+ {/* Title */} +
+ New Donation +
+ + {/* First Name Label */} +
+ First Name +
+ + {/* First Name Input */} +
+ setFirstName(e.target.value)} + placeholder="Enter First Name" + className={inputClass} + /> +
+ + {/* Last Name Label */} +
+ Last Name +
+ + {/* Last Name Input */} +
+ setLastName(e.target.value)} + placeholder="Enter Last Name" + className={inputClass} + /> +
+ + {/* Email Label */} +
+ Email +
+ + {/* Email Input */} +
+ setEmail(e.target.value)} + placeholder="Enter Email Address" + className={inputClass} + /> +
+ + {/* Amount Label */} +
+ Amount +
+ + {/* Amount Input */} +
+ setAmount(e.target.value)} + placeholder="Enter Amount" + className={inputClass} + /> +
+ + {/* Date Label */} +
+ Date +
+ + {/* Date Input */} +
+
+ + {date ? date : 'MM/DD/YYYY'} + + setDate(e.target.value)} + placeholder="MM/DD/YYYY" + maxLength={10} + className="absolute inset-0 w-full bg-transparent border-none outline-none text-neutral-500 text-xl font-normal font-['Source_Sans_Pro'] placeholder:text-neutral-500" + /> +
+ +
+ + {/* Reason Label */} +
+ Reason +
+ + {/* Reason Textarea */} +
+