Skip to content

Commit 3fe6bcf

Browse files
authored
Merge pull request #12 from codersforcauses/user_dashboard
Merging User Side Frontend and Backend with friends implementation, and partial inventory and organization frontend implementation
2 parents 8801921 + 6fb9999 commit 3fe6bcf

52 files changed

Lines changed: 2515 additions & 94 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

client/.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
REACT_EDITOR=code
22

33
APP_ENV=DEVELOPMENT
4-
NEXT_PUBLIC_BACKEND_URL="http://localhost:8000/api"
4+
# NEXT_PUBLIC_BACKEND_URL="http://localhost:8000/api"
5+
NEXT_PUBLIC_BACKEND_URL="http://127.0.0.1:8000"

client/package-lock.json

Lines changed: 0 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/src/components/ui/navbar_organization.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,10 @@ const Header = () => {
8787
// to prevent the blur event from firing when they are clicked.
8888
onMouseDown={(e) => e.preventDefault()}
8989
>
90-
<button className="dropdown-item">Switch to Client</button>
90+
<Link href="/user_dashboard" className="dropdown-item">
91+
{/* <button className="dropdown-item">Switch to Client</button> */}
92+
<button>Switch to Client</button>
93+
</Link>
9194
<button className="dropdown-item">Logout</button>
9295
</div>
9396
)}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { removeFriend, sendFriendRequest } from "../../../lib/api/friends";
2+
import { OtherUsers } from "../user_tables/user_friends_add_table";
3+
4+
const FriendAddItemModal = ({
5+
user,
6+
onClose,
7+
}: {
8+
user: OtherUsers;
9+
onClose: () => void;
10+
}) => {
11+
const handleSend = async () => {
12+
await sendFriendRequest(user.id);
13+
onClose();
14+
};
15+
16+
const handleRemove = async () => {
17+
await removeFriend(user.id);
18+
onClose();
19+
};
20+
21+
return (
22+
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-40">
23+
<div className="w-[300px] rounded bg-white p-6">
24+
<h2 className="text-lg font-bold">{user.username}</h2>
25+
26+
<div className="mt-4 space-y-2">
27+
{!user.is_friend && !user.request_sent && (
28+
<button
29+
onClick={handleSend}
30+
className="w-full rounded bg-blue-600 py-2 text-white"
31+
>
32+
Send Friend Request
33+
</button>
34+
)}
35+
36+
{user.is_friend && (
37+
<button
38+
onClick={handleRemove}
39+
className="w-full rounded bg-red-600 py-2 text-white"
40+
>
41+
Remove Friend
42+
</button>
43+
)}
44+
45+
<button onClick={onClose} className="w-full rounded border py-2">
46+
Close
47+
</button>
48+
</div>
49+
</div>
50+
</div>
51+
);
52+
};
53+
54+
export default FriendAddItemModal;
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// src/components/popups/user_groups_select_popup.tsx
2+
3+
// import Link from "next/link";
4+
// import React from "react";
5+
import React, { useEffect, useState } from "react";
6+
7+
import {
8+
acceptFriendRequest,
9+
declineFriendRequest,
10+
getIncomingRequests,
11+
} from "../../../lib/api/friends";
12+
13+
export type FriendRequest = {
14+
id: number;
15+
sender: {
16+
id: number;
17+
username: string;
18+
};
19+
};
20+
21+
type Props = {
22+
isOpen: boolean;
23+
onClose: () => void;
24+
};
25+
26+
function UserFriendsRecievedPopup({ isOpen, onClose }: Props) {
27+
const [requests, setRequests] = useState<FriendRequest[]>([]);
28+
const [loading, setLoading] = useState(false);
29+
useEffect(() => {
30+
if (!isOpen) return;
31+
32+
setLoading(true);
33+
getIncomingRequests()
34+
.then((res) => {
35+
console.log("Incoming requests:", res.data);
36+
setRequests(res.data);
37+
})
38+
39+
.finally(() => setLoading(false));
40+
}, [isOpen]);
41+
42+
if (!isOpen) return null;
43+
return (
44+
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
45+
<div className="w-full max-w-md rounded-lg bg-white p-4 shadow-lg">
46+
<div className="mb-3 flex items-center justify-between">
47+
<h2 className="text-lg font-bold">Friend Requests</h2>
48+
<button onClick={onClose} className="text-gray-500 hover:text-black">
49+
50+
</button>
51+
</div>
52+
53+
{loading && <p className="text-gray-500">Loading…</p>}
54+
55+
{!loading && requests.length === 0 && (
56+
<p className="text-gray-500">No friend requests.</p>
57+
)}
58+
59+
<div className="space-y-2">
60+
{requests.map((r) => (
61+
<div
62+
key={r.id}
63+
className="flex items-center justify-between rounded border px-3 py-2"
64+
>
65+
<span className="font-medium">{r.sender.username}</span>
66+
67+
<div className="flex gap-2">
68+
<button
69+
onClick={() =>
70+
acceptFriendRequest(r.id).then(() =>
71+
setRequests((prev) =>
72+
prev.filter((req) => req.id !== r.id),
73+
),
74+
)
75+
}
76+
className="rounded bg-green-600 px-2 py-1 text-sm text-white"
77+
>
78+
Accept
79+
</button>
80+
81+
<button
82+
onClick={() =>
83+
declineFriendRequest(r.id).then(() =>
84+
setRequests((prev) =>
85+
prev.filter((req) => req.id !== r.id),
86+
),
87+
)
88+
}
89+
className="rounded bg-red-500 px-2 py-1 text-sm text-white"
90+
>
91+
Reject
92+
</button>
93+
</div>
94+
</div>
95+
))}
96+
</div>
97+
</div>
98+
</div>
99+
);
100+
}
101+
export default UserFriendsRecievedPopup;
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// src/components/popups/user_groups_add_popup.tsx
2+
3+
import Link from "next/link";
4+
import React from "react";
5+
6+
type ItemModalProps = {
7+
// user={selectedItem;
8+
isOpen: boolean;
9+
onClose: () => void;
10+
};
11+
12+
function UserFriendsSearchPopup({ isOpen, onClose }: ItemModalProps) {
13+
if (!isOpen) return null;
14+
return (
15+
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
16+
<div className="absolute inset-0" onClick={onClose} />
17+
<div className="absolute w-full max-w-md rounded-xl bg-white p-6 shadow-lg">
18+
{/* Header */}
19+
<div className="flex items-center justify-between border-b pb-3">
20+
<h2 className="text-lg font-semibold">Add Friends</h2>
21+
<button
22+
onClick={onClose}
23+
className="text-gray-500 hover:text-gray-800"
24+
>
25+
26+
</button>
27+
</div>
28+
29+
{/* Body */}
30+
<div className="space-y-2 py-4">
31+
{/* Start */}
32+
<div className="w-full min-w-[200px] max-w-sm">
33+
<div className="relative">
34+
<input
35+
className="ease w-full rounded-md border border-slate-200 bg-transparent py-2 pl-3 pr-28 text-sm text-slate-700 shadow-sm transition duration-300 placeholder:text-slate-400 hover:border-slate-300 focus:border-slate-400 focus:shadow focus:outline-none"
36+
placeholder="Eg., Ky Kiske"
37+
/>
38+
<button
39+
type="button"
40+
className="absolute right-1 top-1 flex items-center rounded border border-transparent bg-slate-800 px-2.5 py-1 text-center text-sm text-white shadow-sm transition-all hover:bg-slate-700 hover:shadow focus:bg-slate-700 focus:shadow-none active:bg-slate-700 active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
41+
>
42+
<svg
43+
xmlns="http://www.w3.org/2000/svg"
44+
viewBox="0 0 24 24"
45+
fill="currentColor"
46+
className="mr-2 h-4 w-4"
47+
>
48+
<path
49+
fill-rule="evenodd"
50+
d="M10.5 3.75a6.75 6.75 0 1 0 0 13.5 6.75 6.75 0 0 0 0-13.5ZM2.25 10.5a8.25 8.25 0 1 1 14.59 5.28l4.69 4.69a.75.75 0 1 1-1.06 1.06l-4.69-4.69A8.25 8.25 0 0 1 2.25 10.5Z"
51+
clip-rule="evenodd"
52+
/>
53+
</svg>
54+
Search
55+
</button>
56+
</div>
57+
</div>
58+
{/* End */}
59+
{/* <p><strong>ID:</strong> Ummm ~~ </p> */}
60+
</div>
61+
62+
{/* Footer */}
63+
<div className="flex justify-end gap-3 border-t pt-4">
64+
<Link href="../../../user_friends_search/">
65+
<button className="rounded bg-gray-200 px-4 py-2 hover:bg-gray-300">
66+
Expand
67+
</button>
68+
</Link>
69+
<button
70+
onClick={onClose}
71+
className="rounded bg-gray-200 px-4 py-2 hover:bg-gray-300"
72+
>
73+
Close
74+
</button>
75+
<button className="rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700">
76+
Edit
77+
</button>
78+
</div>
79+
</div>
80+
</div>
81+
);
82+
}
83+
export default UserFriendsSearchPopup;

0 commit comments

Comments
 (0)