Skip to content

Commit

Permalink
refactor(all): add events collection. Home page based on user.role (#…
Browse files Browse the repository at this point in the history
…14)

- **Refactored `Home`**:
- Adjusted logic to render `DonorDashboard` or `OrganizationDashboard`
based on `user.role`.

- **Firebase Updates**:
  - Added an `events` collection to centralize event management.
  - Updated the user schema:
- Added `joinedEvents` as an array of event IDs for both `DonorProfile`
and `OrganizationProfile`.

- **Component Updates**:
- Updated `DonationModal` to align with the new `DonationEvent` schema
(1:1 relationship between donor and event).
- Enhanced `Schedule` to fetch and display events dynamically, adding
visual indicators for event dates on the calendar.

- **Hook Improvements**:
- Enhanced `useEvents` to handle creating, updating, and deleting events
in the `events` collection.
  - Streamlined `useUser` for role-based event logic.

- **Type Updates**:
- Simplified and refined the `DonationEvent` type for better clarity and
alignment with the new schema.

### Breaking Changes:
- Migrated to a centralized `events` collection; users now reference
events via `joinedEvents`.

---------

Co-authored-by: MC2b6 <[email protected]>
  • Loading branch information
ZL-Asica and marycaserio authored Nov 21, 2024
1 parent afec091 commit 22e849c
Show file tree
Hide file tree
Showing 30 changed files with 1,373 additions and 1,204 deletions.
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

0 comments on commit 22e849c

Please sign in to comment.