Skip to content

Commit 51ff3fd

Browse files
authored
Merge pull request #48 from WildCodeSchool/US00-Mobile-second-part
Mobile discussion et améliorations style global
2 parents 228888e + c033f30 commit 51ff3fd

37 files changed

+1511
-297
lines changed

backend/src/entities/Group.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class Group extends BaseEntity {
4545
@Field()
4646
event_type: string;
4747

48-
@Column()
48+
@Column({ default: 0 })
4949
@Field()
5050
piggy_bank: number;
5151

backend/src/resolvers/GroupResolver.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ class CreateGroupInput {
2828
@Field()
2929
event_type!: string;
3030

31-
@Field()
32-
piggy_bank!: number;
31+
@Field({ nullable: true, defaultValue: 0 })
32+
piggy_bank?: number;
3333

3434
@Field()
3535
deadline!: Date;
@@ -40,6 +40,15 @@ class CreateGroupInput {
4040
user_beneficiary?: string;
4141
}
4242

43+
@InputType()
44+
class AddFundsInput {
45+
@Field()
46+
groupId!: number;
47+
48+
@Field()
49+
amount!: number;
50+
}
51+
4352
@ObjectType()
4453
export class MyGroupsResponse {
4554
@Field(() => [Group])
@@ -121,7 +130,7 @@ export default class GroupResolver {
121130
user_admin: userAdmin,
122131
name: data.name,
123132
event_type: data.event_type,
124-
piggy_bank: data.piggy_bank,
133+
piggy_bank: data.piggy_bank ?? 0,
125134
deadline: data.deadline,
126135
user_beneficiary: beneficiaryUser ?? undefined,
127136
});
@@ -156,4 +165,34 @@ export default class GroupResolver {
156165

157166
return group;
158167
}
168+
169+
@UseMiddleware(RoleMiddleware())
170+
@Mutation(() => Group)
171+
async addFundsToGroup(@Arg("data") data: AddFundsInput, @Ctx() ctx: ContextType) {
172+
if (!ctx.user) throw new Error("Utilisateur non connecté");
173+
174+
// Vérifier que le groupe existe
175+
const group = await Group.findOne({
176+
where: { id: data.groupId },
177+
relations: { groupMember: true },
178+
});
179+
180+
if (!group) throw new Error("Groupe introuvable");
181+
182+
// Vérifier que l'utilisateur est membre du groupe
183+
const isMember = await GroupMember.findOne({
184+
where: { groupId: data.groupId, userId: ctx.user.id },
185+
});
186+
187+
if (!isMember) throw new Error("Vous n'êtes pas membre de ce groupe");
188+
189+
// Vérifier que le montant est positif
190+
if (data.amount <= 0) throw new Error("Le montant doit être positif");
191+
192+
// Ajouter les fonds à la cagnotte
193+
group.piggy_bank += data.amount;
194+
await group.save();
195+
196+
return group;
197+
}
159198
}

frontend/src/components/Wishlist.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,6 @@ export default function Wishlist() {
151151
<div className="flex flex-col items-center justify-center text-white">
152152
<Icon icon="gift" className="text-7xl opacity-80 mb-3" />
153153
<p className="text-lg mb-8">Aucune idée pour l'instant.</p>
154-
<Button
155-
type="button"
156-
icon="plus"
157-
text="Ajouter une idée"
158-
colour="green"
159-
onClick={addModal.open}
160-
className="px-4 py-2 rounded-xl"
161-
/>
162154
</div>
163155
</div>
164156
) : (

frontend/src/components/auth/AuthFormTemplate.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function AuthFormTemplate({ title, children, onSubmit, footer }:
1515
</Title>
1616
<div className="flex flex-col justify-start w-full flex-shrink-0">
1717
<form
18-
className="flex flex-col items-center gap-3 justify-center w-full max-w-[600px] md:w-auto md:max-w-none"
18+
className="flex flex-col items-center gap-4 justify-center w-full max-w-[600px] md:w-auto md:max-w-none"
1919
onSubmit={onSubmit}
2020
>
2121
{children}

frontend/src/components/auth/auth.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
align-items: center;
5656
justify-content: center;
5757
text-align: center;
58-
font-size: 60px;
58+
font-size: 75px;
59+
line-height: 1;
5960
font-weight: 400;
6061
color: #fdfbf6;
6162
}

frontend/src/components/forms/CreateGroupForm.tsx

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useCreateGroupMutation } from "../../graphql/generated/graphql-types";
44
import { GET_ALL_MY_GROUPS } from "../../graphql/operations/groupOperations";
55
import { groupCreationFormValidation } from "../../hooks/formValidationRules";
66
import { useSanitizedForm } from "../../hooks/useSanitizedForm";
7-
import Button from "../utils/Button";
87
import Icon from "../utils/Icon";
98
import Input from "../utils/Input";
109
import InputWithToggle from "../utils/InputWithToggle";
@@ -15,9 +14,10 @@ import GroupLink from "./GroupLink";
1514

1615
type CreateGroupFormProps = {
1716
onSuccess?: () => void;
17+
onCancel?: () => void;
1818
};
1919

20-
export default function CreateGroupForm({ onSuccess }: CreateGroupFormProps) {
20+
export default function CreateGroupForm({ onSuccess, onCancel }: CreateGroupFormProps) {
2121
const options = [
2222
{
2323
label: "Anniversaire",
@@ -121,14 +121,18 @@ export default function CreateGroupForm({ onSuccess }: CreateGroupFormProps) {
121121
}
122122

123123
return (
124-
<form className=" flex w-full h-full rounded-2xl" onSubmit={handleSubmit} autoComplete="off">
125-
<div className="bg-green w-1/2 h-full flex flex-col justify-center pt-10 pb-5 rounded-tl-2xl rounded-bl-2xl">
124+
<form
125+
className="flex w-full h-full rounded-2xl max-md:flex-col max-md:bg-green max-md:rounded-none max-md:overflow-y-auto max-md:p-8 max-md:justify-center"
126+
onSubmit={handleSubmit}
127+
autoComplete="off"
128+
>
129+
<div className="bg-green w-1/2 h-full flex flex-col justify-center pt-10 pb-5 rounded-tl-2xl rounded-bl-2xl max-md:w-full max-md:rounded-none max-md:pt-0 max-md:pb-0">
126130
{/* Form to create a new group */}
127-
<Subtitle className="text-center text-2xl">Créer un groupe</Subtitle>
128-
<div className="text-white text-8xl m-auto">
131+
<Subtitle className="text-center text-2xl max-md:text-xl max-md:mb-10">Créer un groupe</Subtitle>
132+
<div className="text-white text-8xl m-auto max-md:hidden">
129133
<Icon icon="image" />
130134
</div>
131-
<div className="flex flex-col gap-4 px-20">
135+
<div className="flex flex-col gap-4 px-20 max-md:px-0">
132136
<Input
133137
name="name"
134138
type="text"
@@ -154,16 +158,6 @@ export default function CreateGroupForm({ onSuccess }: CreateGroupFormProps) {
154158
theme="light"
155159
/>
156160

157-
<Input
158-
name="piggy_bank"
159-
type="number"
160-
value={String(formData.piggy_bank)}
161-
onChange={handleChange}
162-
placeholder={String(0)}
163-
error={errors.piggy_bank}
164-
icon="dollar"
165-
/>
166-
167161
<InputWithToggle
168162
checked={checked}
169163
onCheckedChange={() => {
@@ -185,20 +179,28 @@ export default function CreateGroupForm({ onSuccess }: CreateGroupFormProps) {
185179
error={errors.deadline}
186180
/>
187181
</div>
188-
<Button
189-
type="submit"
190-
text="Créer le groupe"
191-
className="text-center w-fit px-8 py-1 m-auto text-lg"
192-
colour="dark"
193-
rounded
194-
>
195-
Créer
196-
</Button>
182+
<div className="flex flex-col gap-6 max-md:w-full max-md:mt-8">
183+
<button
184+
type="submit"
185+
className="bg-dark text-white font-inter-extra-bold rounded-lg py-2 px-8 w-fit m-auto text-lg shadow-md hover:brightness-110 max-md:w-full max-md:py-3 max-md:rounded-full max-md:text-base max-md:font-bold max-md:shadow-[0_2px_6px_rgba(32,9,4,0.2)] max-md:bg-white max-md:text-dark max-md:hover:bg-gray-100"
186+
>
187+
Créer le groupe
188+
</button>
189+
{onCancel && (
190+
<button
191+
type="button"
192+
onClick={onCancel}
193+
className="hidden max-md:block w-full py-3 rounded-full bg-dark text-white text-base font-bold shadow-[0_2px_6px_rgba(32,9,4,0.2)] hover:bg-[#463835]"
194+
>
195+
Annuler
196+
</button>
197+
)}
198+
</div>
197199
{error && <p className="text-orange font-inter text-sm pt-1 text-center">{error}</p>}
198200
{errors.main && <p className="text-orange font-inter text-sm pt-1 text-center">{errors.main}</p>}
199201
</div>
200202

201-
<div className="w-1/2 bg-white max-md:w-full flex flex-col max-md:rounded-none rounded-tr-2xl rounded-br-2xl">
203+
<div className="w-1/2 bg-white h-full flex flex-col rounded-tr-2xl rounded-br-2xl max-md:hidden">
202204
<div className="flex flex-col gap-4 px-20 m-auto">
203205
{/* Adding users can go here */}
204206
<div className="flex flex-row items-center w-full border border-blue">
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { useState } from "react";
2+
import { useAddFundsToGroupMutation } from "../../graphql/generated/graphql-types";
3+
import { GET_ALL_MY_GROUPS } from "../../graphql/operations/groupOperations";
4+
import Button from "../utils/Button";
5+
import Input from "../utils/Input";
6+
import Modal from "../utils/Modal";
7+
8+
type AddFundsModalProps = {
9+
isOpen: boolean;
10+
onClose: () => void;
11+
onSuccess?: () => void;
12+
groupId: number;
13+
currentAmount: number;
14+
};
15+
16+
export default function AddFundsModal({
17+
isOpen,
18+
onClose,
19+
onSuccess,
20+
groupId,
21+
currentAmount,
22+
}: AddFundsModalProps) {
23+
const [amount, setAmount] = useState<string>("");
24+
const [error, setError] = useState<string>("");
25+
26+
const [addFunds, { loading }] = useAddFundsToGroupMutation({
27+
refetchQueries: [{ query: GET_ALL_MY_GROUPS }],
28+
awaitRefetchQueries: true,
29+
});
30+
31+
const handleSubmit = async (e: React.FormEvent) => {
32+
e.preventDefault();
33+
setError("");
34+
35+
const numAmount = Number(amount);
36+
if (!amount || numAmount <= 0) {
37+
setError("Veuillez entrer un montant valide");
38+
return;
39+
}
40+
41+
try {
42+
await addFunds({
43+
variables: {
44+
data: {
45+
groupId,
46+
amount: numAmount,
47+
},
48+
},
49+
});
50+
setAmount("");
51+
onSuccess?.();
52+
onClose();
53+
} catch (err) {
54+
if (err instanceof Error) {
55+
setError(err.message);
56+
} else {
57+
setError("Une erreur est survenue");
58+
}
59+
}
60+
};
61+
62+
const handleClose = () => {
63+
setAmount("");
64+
setError("");
65+
onClose();
66+
};
67+
68+
return (
69+
<Modal
70+
isOpen={isOpen}
71+
onClose={handleClose}
72+
className="!w-[450px] !h-auto max-md:!h-auto max-md:!w-11/12 max-md:!rounded-2xl !bg-yellow"
73+
>
74+
<form onSubmit={handleSubmit} className="p-10 flex flex-col gap-8 bg-yellow rounded-2xl min-w-[350px]">
75+
<h2 className="text-3xl font-inter-extra-bold text-white text-center mb-2">Ajouter des fonds</h2>
76+
77+
<div className="text-center">
78+
<p className="text-white text-lg mb-1">Cagnotte actuelle</p>
79+
<p className="font-bold text-white text-4xl">{currentAmount}</p>
80+
</div>
81+
82+
<div className="mt-2">
83+
<Input
84+
name="amount"
85+
type="number"
86+
value={amount}
87+
onChange={(e) => setAmount(e.target.value)}
88+
placeholder="Montant à ajouter (€)"
89+
icon="piggyBank"
90+
error={error}
91+
/>
92+
</div>
93+
94+
<div className="flex gap-4 justify-center mt-4">
95+
<Button type="button" colour="orange" onClick={handleClose}>
96+
Annuler
97+
</Button>
98+
<Button type="submit" colour="green">
99+
{loading ? "..." : "Ajouter"}
100+
</Button>
101+
</div>
102+
</form>
103+
</Modal>
104+
);
105+
}

frontend/src/components/groups/Groups.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ type GroupsProps = {
1717
messages: Record<number, Message[]>;
1818
getNbNewMessages: (groupId: number, messages: Message[]) => number;
1919
updateLastVu: (groupId: number, date: Date | string, serveurSyconization?: boolean) => void;
20+
onGroupClick?: (group: GetAllMyGroupsQuery["getAllMyGroups"]["groups"][number]) => void;
21+
activeGroupId?: number;
2022
};
2123

2224
export default function Groups({
@@ -25,6 +27,8 @@ export default function Groups({
2527
loading,
2628
error,
2729
messages,
30+
onGroupClick,
31+
activeGroupId,
2832
getNbNewMessages,
2933
updateLastVu,
3034
}: GroupsProps) {
@@ -37,7 +41,8 @@ export default function Groups({
3741
<>
3842
<Container
3943
colour="blue"
40-
title="Mes Groupes"
44+
title="Mes groupes"
45+
classNameTitle="text-[1.125rem]"
4146
button={
4247
<Button text={"Ajouter un groupe"} icon="plus" colour="green" onClick={createGroupModal.open} />
4348
}
@@ -51,13 +56,15 @@ export default function Groups({
5156
key={group.id}
5257
id={Number(group.id)}
5358
title={group.name}
59+
active={activeGroupId === Number(group.id)}
5460
onClick={() => {
5561
setActiveGroup?.(group);
5662
updateLastVu(Number(group.id), messages[Number(group.id)][0].createdAt);
63+
onGroupClick?.(group);
5764
}}
5865
nbNewMessages={getNbNewMessages(Number(group.id), messages[Number(group.id)] || [])}
5966
>
60-
<p className="text-gray-600 text-sm sm:text-base truncate overflow-hidden text-ellipsis whitespace-nowrap">
67+
<p className="text-gray-600 text-xs sm:text-sm leading-tight">
6168
<span> Date limite: {formatDate(new Date(group.deadline))} </span> <br />
6269
<span>
6370
{group.groupMember?.length}{" "}

frontend/src/components/groups/Messaging/Message.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default function Message({ regroupement, userId }: MessageProps) {
4949
{regroupement.map((message, index) => {
5050
return (
5151
<div
52-
className={`w-[320px] border-[1px] px-[16px] py-[10px] ${defClassRadius(regroupement.length, index + 1, isAutreMessage)} ${defClassColor(isAutreMessage)}`}
52+
className={`w-[250px] md:w-[320px] border-[1px] px-[16px] py-[10px] ${defClassRadius(regroupement.length, index + 1, isAutreMessage)} ${defClassColor(isAutreMessage)}`}
5353
key={message.id}
5454
>
5555
<p className="text-[16px] leading-[1.25]">{message.content}</p>
@@ -68,7 +68,7 @@ export default function Message({ regroupement, userId }: MessageProps) {
6868
<img
6969
src={getProfilePictureUrl(regroupement[0].user.image_url)}
7070
alt="profile utilisateur"
71-
className="w-[60px] h-[60px] rounded-full object-cover"
71+
className="w-[40px] h-[40px] md:w-[60px] md:h-[60px] rounded-full object-cover"
7272
/>
7373
</div>
7474
</div>

0 commit comments

Comments
 (0)