Skip to content
This repository has been archived by the owner on Nov 26, 2024. It is now read-only.

Commit

Permalink
feat(editable): transactions + participant
Browse files Browse the repository at this point in the history
  • Loading branch information
cedricpoon committed Oct 23, 2024
1 parent 1c7897b commit ff3e676
Show file tree
Hide file tree
Showing 5 changed files with 349 additions and 98 deletions.
27 changes: 16 additions & 11 deletions src/pages/Balance.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@ function Balance() {
const participants = useSelector((state) => state.transactions.participants);
const transactions = useSelector((state) => state.transactions.transactions);

const participantMap = participants.reduce((acc, p) => {
acc[p.id] = p.name;
return acc;
}, {});

const calculateBalances = () => {
const balances = {};
participants.forEach((p) => {
balances[p.name] = 0;
balances[p.id] = 0;
});

transactions.forEach((t) => {
const splitAmount = t.amount / t.participants.length;
t.participants.forEach((p) => {
if (p !== t.paidBy) {
balances[p] -= splitAmount;
t.participants.forEach((pId) => {
if (pId !== t.paidBy) {
balances[pId] -= splitAmount;
balances[t.paidBy] += splitAmount;
}
});
Expand All @@ -26,11 +31,11 @@ function Balance() {
const debtors = [];
const creditors = [];

Object.keys(balances).forEach((person) => {
if (balances[person] < 0) {
debtors.push({ name: person, amount: -balances[person] });
} else if (balances[person] > 0) {
creditors.push({ name: person, amount: balances[person] });
Object.keys(balances).forEach((pId) => {
if (balances[pId] < -0.01) {
debtors.push({ id: pId, amount: -balances[pId] });
} else if (balances[pId] > 0.01) {
creditors.push({ id: pId, amount: balances[pId] });
}
});

Expand All @@ -44,8 +49,8 @@ function Balance() {

const settledAmount = Math.min(remaining, creditor.amount);
settlements.push({
from: debtor.name,
to: creditor.name,
from: participantMap[debtor.id],
to: participantMap[creditor.id],
amount: settledAmount.toFixed(2),
});
creditor.amount -= settledAmount;
Expand Down
104 changes: 75 additions & 29 deletions src/pages/Participants.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addParticipant } from '../redux/slices/transactionsSlice';
import { addParticipant, editParticipant, deleteParticipant } from '../redux/slices/transactionsSlice';
import {
Container,
Typography,
Expand All @@ -11,48 +11,58 @@ import {
List,
ListItem,
ListItemText,
Snackbar,
Alert,
IconButton,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
} from '@mui/material';
import Slide from '@mui/material/Slide';

// Optional: Slide Transition for Snackbar
function SlideTransition(props) {
return <Slide {...props} direction="down" />;
}
import { Edit as EditIcon, Delete as DeleteIcon } from '@mui/icons-material';

function Participants() {
const participants = useSelector((state) => state.transactions.participants);
const dispatch = useDispatch();
const [name, setName] = useState('');
const [open, setOpen] = useState(false);

// State for editing
const [editDialogOpen, setEditDialogOpen] = useState(false);
const [currentParticipant, setCurrentParticipant] = useState(null);
const [editName, setEditName] = useState('');

const handleAdd = () => {
if (name.trim()) {
dispatch(addParticipant({ id: Date.now(), name }));
dispatch(addParticipant({ id: Date.now(), name: name.trim() }));
setName('');
setOpen(true);
}
};

const handleEditOpen = (participant) => {
setCurrentParticipant(participant);
setEditName(participant.name);
setEditDialogOpen(true);
};

const handleEditClose = () => {
setEditDialogOpen(false);
setCurrentParticipant(null);
};

const handleEditSave = () => {
if (editName.trim()) {
dispatch(editParticipant({
id: currentParticipant.id,
updatedParticipant: { name: editName.trim() },
}));
handleEditClose();
}
};

const handleDelete = (id) => {
dispatch(deleteParticipant(id));
};

return (
<Container>
<Snackbar
open={open}
autoHideDuration={6000}
onClose={() => setOpen(false)}
anchorOrigin={{ vertical: 'top', horizontal: 'center' }} // Positioning at top-center
TransitionComponent={SlideTransition} // Adding slide transition
>
<Alert
onClose={() => setOpen(false)}
severity="success"
sx={{ width: '100%', fontSize: '1.2rem', fontWeight: 'bold' }} // Enhanced styling
variant="filled" // Filled variant for higher visibility
>
Participant added successfully!
</Alert>
</Snackbar>
<Typography variant="h4" gutterBottom sx={{ mt: 4 }}>
Participants
</Typography>
Expand All @@ -76,11 +86,47 @@ function Participants() {
</Paper>
<List>
{participants.map((p) => (
<ListItem key={p.id} divider>
<ListItem
key={p.id}
divider
secondaryAction={
<>
<IconButton edge="end" aria-label="edit" onClick={() => handleEditOpen(p)}>
<EditIcon />
</IconButton>
<IconButton edge="end" aria-label="delete" onClick={() => handleDelete(p.id)}>
<DeleteIcon />
</IconButton>
</>
}
>
<ListItemText primary={p.name} />
</ListItem>
))}
</List>

{/* Edit Participant Dialog */}
<Dialog open={editDialogOpen} onClose={handleEditClose}>
<DialogTitle>Edit Participant</DialogTitle>
<DialogContent>
<TextField
fullWidth
label="Participant Name"
variant="outlined"
value={editName}
onChange={(e) => setEditName(e.target.value)}
sx={{ mt: 2 }}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleEditClose} color="secondary">
Cancel
</Button>
<Button onClick={handleEditSave} color="primary" variant="contained">
Save
</Button>
</DialogActions>
</Dialog>
</Container>
);
}
Expand Down
Loading

0 comments on commit ff3e676

Please sign in to comment.