Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(all): add events collection. Home page based on user.role #14

Merged
merged 6 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
955 changes: 389 additions & 566 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,15 @@
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@fontsource/roboto": "^5.1.0",
"@mui/icons-material": "^6.1.7",
"@mui/icons-material": "^6.1.8",
"@mui/lab": "^6.0.0-beta.15",
"@mui/material": "^6.1.7",
"@mui/x-date-pickers": "^7.22.2",
"@mui/x-date-pickers": "^7.22.3",
"@zl-asica/react": "^0.3.4",
"date-fns": "^4.1.0",
"dayjs": "^1.11.13",
"es-toolkit": "^1.27.0",
"firebase": "^11.0.2",
"moment": "^2.30.1",
"react": "^18.3.1",
"react-big-calendar": "^1.15.0",
"react-dom": "^18.3.1",
"react-router-dom": "^6.28.0"
},
Expand Down
35 changes: 16 additions & 19 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { ThemeProvider } from '@mui/material';
import { BrowserRouter as Router } from 'react-router-dom';

import { UserProvider } from '@/context/UserContext';
import { EventsProvider } from '@/context/EventsContext';
import AppRoutes from '@/routes';

import { Header, Footer } from '@/components/common';
Expand All @@ -15,25 +14,23 @@ const App = () => {
return (
<ThemeProvider theme={theme}>
<UserProvider>
<EventsProvider>
<div className='App'>
<Router
future={{
v7_relativeSplatPath: true,
v7_startTransition: true,
}}
>
<Header />
<div className='content'>
{/* Main content area where pages will render */}
<AppRoutes />
</div>
<div className='App'>
<Router
future={{
v7_relativeSplatPath: true,
v7_startTransition: true,
}}
>
<Header />
<div className='content'>
{/* Main content area where pages will render */}
<AppRoutes />
</div>

{/* Bottom Navigation with React Router links */}
<Footer />
</Router>
</div>
</EventsProvider>
{/* Bottom Navigation with React Router links */}
<Footer />
</Router>
</div>
</UserProvider>
</ThemeProvider>
);
Expand Down
199 changes: 199 additions & 0 deletions src/components/Home/DonorDashboard/DonationModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import { useState } from 'react';
import {
Modal,
Box,
Typography,
Button,
RadioGroup,
FormControlLabel,
Radio,
Divider,
} from '@mui/material';
import { LocalizationProvider, DateTimePicker } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import type dayjs from 'dayjs';

import { useEvents } from '@/hooks';

import { MessageDialog } from '@/components/common';

interface DonationModalProps {
open: boolean;
onClose: () => void;
organization: OrganizationProfile;
selectedNeeds: string[];
donor: DonorProfile;
}

const DonationModal = ({
open,
onClose,
organization,
selectedNeeds,
donor,
}: DonationModalProps) => {
const [method, setMethod] = useState<string>('drop-off');
const [selectedTime, setSelectedTime] = useState<dayjs.Dayjs | null>(null);
const [openMessageDialog, setOpenMessageDialog] = useState(false);
const [message, setMessage] = useState<string>('');
const { addOrUpdateEvent } = useEvents();

const handleConfirm = async () => {
if (selectedNeeds.length === 0 || !selectedTime || !method) {
setMessage('Please fill out all fields and select at least one need.');
setOpenMessageDialog(true);
return;
}

const newEvent: DonationEvent = {
eventId: `${organization.uid}-${donor.uid}-${new Date().toISOString()}`, // Unique ID
organizationId: organization.uid,
donorId: donor.uid,
title: `Donation to ${organization.name}`,
description: `Donation of items: ${selectedNeeds.join(', ')}`,
date: selectedTime!.toDate(), // Ensure selectedTime is not null
supplies: selectedNeeds.map(
(item) =>
({
itemName: item,
quantityNeeded: 1, // Default assumption
quantityProvided: 1, // Donor provides these items
providedBy: [donor.uid], // Add the donor ID
status: true,
}) as Supply
),
};

try {
// Add or update the event using the useEvents hook
await addOrUpdateEvent(newEvent);

setMessage('Donation successfully added to your schedule!');
setOpenMessageDialog(true);
onClose(); // Close the modal
} catch (error) {
console.error('Error adding/updating event:', error);
setMessage('Failed to schedule donation. Please try again.');
setOpenMessageDialog(true);
}
};

return (
<>
<Modal
open={open}
onClose={onClose}
disableEnforceFocus
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
margin: 5,
}}
>
<Box
sx={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
bgcolor: 'background.paper',
boxShadow: 24,
p: 4,
borderRadius: 3,
width: '90%',
maxWidth: 500,
}}
>
<Typography
variant='h6'
fontWeight='bold'
mb={3}
textAlign='center'
>
Schedule Your Donation
</Typography>
<Divider sx={{ mb: 3 }} />
<Box sx={{ mb: 3 }}>
<Typography
variant='subtitle1'
fontWeight='bold'
mb={1}
>
Select a Delivery Method:
</Typography>
<RadioGroup
value={method}
onChange={(e) => setMethod(e.target.value)}
>
<FormControlLabel
value='drop-off'
control={<Radio />}
label='Drop-off'
/>
{organization.pickup && (
<FormControlLabel
value='pick-up'
control={<Radio />}
label='Pick-up'
/>
)}
</RadioGroup>
</Box>
<Box sx={{ mb: 3 }}>
<Typography
variant='subtitle1'
fontWeight='bold'
mb={1}
>
Select a Time:
</Typography>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DateTimePicker
value={selectedTime}
onChange={setSelectedTime}
slotProps={{
textField: {
fullWidth: true,
sx: {
'& .MuiInputBase-root': {
fontSize: '1rem',
},
},
},
}}
/>
</LocalizationProvider>
</Box>
<Divider sx={{ mb: 3 }} />
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
<Button
onClick={onClose}
color='secondary'
size='large'
sx={{ px: 3 }}
>
Cancel
</Button>
<Button
onClick={handleConfirm}
variant='contained'
size='large'
sx={{ px: 3 }}
>
Confirm
</Button>
</Box>
</Box>
</Modal>

<MessageDialog
open={openMessageDialog}
onClose={() => setOpenMessageDialog(false)}
message={message}
/>
</>
);
};

export default DonationModal;
39 changes: 39 additions & 0 deletions src/components/Home/DonorDashboard/NeedList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
List,
ListItem,
Checkbox,
ListItemText,
Typography,
} from '@mui/material';

interface NeedsListProps {
needs: string[];
checkedItems: boolean[];
onToggle: (index: number) => void;
}

const NeedsList = ({ needs, checkedItems, onToggle }: NeedsListProps) => (
<List>
{needs.length > 0 ? (
needs.map((need, index) => (
<ListItem key={index}>
<Checkbox
checked={checkedItems[index]}
onChange={() => onToggle(index)}
/>
<ListItemText primary={need} />
</ListItem>
))
) : (
<Typography
variant='body1'
color='text.secondary'
m={2}
>
No current needs.
</Typography>
)}
</List>
);

export default NeedsList;
Loading
Loading