From 2c1ab6b19d22b30a0654f3ca6fb5d66ab2848043 Mon Sep 17 00:00:00 2001 From: Kamran Ahmed Date: Tue, 8 Aug 2023 19:29:50 +0100 Subject: [PATCH] Accept, reject friends --- src/components/Friends/FriendProgressItem.tsx | 259 ++++++++++++++++++ src/components/Friends/FriendsPage.tsx | 111 +++++++- 2 files changed, 366 insertions(+), 4 deletions(-) create mode 100644 src/components/Friends/FriendProgressItem.tsx diff --git a/src/components/Friends/FriendProgressItem.tsx b/src/components/Friends/FriendProgressItem.tsx new file mode 100644 index 000000000..bc07926ef --- /dev/null +++ b/src/components/Friends/FriendProgressItem.tsx @@ -0,0 +1,259 @@ +import { useState } from 'preact/hooks'; +import type { ListFriendsResponse } from './FriendsPage'; +import { DeleteUserIcon } from '../ReactIcons/DeleteUserIcon'; +import { pageProgressMessage } from '../../stores/page'; +import { httpDelete, httpPost } from '../../lib/http'; +import { useToast } from '../../hooks/use-toast'; +import { TrashIcon } from '../ReactIcons/TrashIcon'; +import { AddedUserIcon } from '../ReactIcons/AddedUserIcon'; +import { AddUserIcon } from '../ReactIcons/AddUserIcon'; + +type FriendProgressItemProps = { + friend: ListFriendsResponse[0]; + onShowResourceProgress: (resourceId: string) => void; + onReload: () => void; +}; + +export function FriendProgressItem(props: FriendProgressItemProps) { + const { friend, onShowResourceProgress, onReload } = props; + const toast = useToast(); + + async function deleteFriend(userId: string, successMessage: string) { + pageProgressMessage.set('Please wait...'); + const { response, error } = await httpDelete( + `${import.meta.env.PUBLIC_API_URL}/v1-delete-friend/${userId}`, + {} + ); + + if (error || !response) { + toast.error(error?.message || 'Something went wrong'); + return; + } + + toast.success(successMessage); + onReload(); + } + + async function addFriend(userId: string, successMessage: string) { + pageProgressMessage.set('Please wait...'); + const { response, error } = await httpPost( + `${import.meta.env.PUBLIC_API_URL}/v1-add-friend/${userId}`, + {} + ); + + if (error || !response) { + toast.error(error?.message || 'Something went wrong'); + return; + } + + toast.success(successMessage); + onReload(); + } + + const roadmaps = (friend.roadmaps || []).sort((a, b) => { + return b.done - a.done; + }); + + const [showAll, setShowAll] = useState(false); + const status = friend.status; + + return ( + <> +
+
+ {friend.name +
+

{friend.name}

+

{friend.email}

+
+
+ {friend.status === 'accepted' && ( +
+ {(showAll ? roadmaps : roadmaps.slice(0, 4)).map((progress) => { + return ( + + ); + })} + + {roadmaps.length > 4 && !showAll && ( + + )} + + {showAll && ( + + )} + + {roadmaps.length === 0 && ( +
No progress
+ )} +
+ )} + + {friend.status === 'rejected' && ( + <> +
+ + + Request Rejected + +
+ + Changed your mind?{' '} + + + + )} + + {friend.status === 'got_rejected' && ( + <> +
+ + + Request Rejected + +
+ + + + + )} + + {friend.status === 'sent' && ( + <> +
+ + + Request Sent + +
+ + + + + )} + + {friend.status === 'received' && ( + <> +
+ + Request Received + + + + +
+ + )} +
+ + ); +} diff --git a/src/components/Friends/FriendsPage.tsx b/src/components/Friends/FriendsPage.tsx index a6b27de6c..305a89996 100644 --- a/src/components/Friends/FriendsPage.tsx +++ b/src/components/Friends/FriendsPage.tsx @@ -6,6 +6,8 @@ import { httpGet } from '../../lib/http'; import type { FriendshipStatus } from '../Befriend'; import { useToast } from '../../hooks/use-toast'; import { EmptyFriends } from './EmptyFriends'; +import { FriendProgressItem } from './FriendProgressItem'; +import UserIcon from '../../icons/user.svg'; type FriendResourceProgress = { updatedAt: string; @@ -18,18 +20,35 @@ type FriendResourceProgress = { total: number; }; -type ListFriendsResponse = { +export type ListFriendsResponse = { userId: string; name: string; + email: string; avatar: string; status: FriendshipStatus; roadmaps: FriendResourceProgress[]; bestPractices: FriendResourceProgress[]; }[]; +type GroupingType = { + label: string; + value: 'active' | 'requests' | 'sent'; + statuses: FriendshipStatus[]; +}; + +const groupingTypes: GroupingType[] = [ + { label: 'Active', value: 'active', statuses: ['accepted'] }, + { label: 'Requests', value: 'requests', statuses: ['received', 'rejected'] }, + { label: 'Sent', value: 'sent', statuses: ['sent', 'got_rejected'] }, +]; + export function FriendsPage() { const toast = useToast(); + + const [isLoading, setIsLoading] = useState(true); const [friends, setFriends] = useState([]); + const [selectedGrouping, setSelectedGrouping] = + useState('active'); async function loadFriends() { const { response, error } = await httpGet( @@ -47,6 +66,7 @@ export function FriendsPage() { useEffect(() => { loadFriends().finally(() => { pageProgressMessage.set(''); + setIsLoading(false); }); }, []); @@ -60,17 +80,100 @@ export function FriendsPage() { return ; } + const selectedGroupingType = groupingTypes.find( + (grouping) => grouping.value === selectedGrouping + ); + + const filteredFriends = friends.filter((friend) => + selectedGroupingType?.statuses.includes(friend.status) + ); + + const receivedRequests = friends.filter( + (friend) => friend.status === 'received' + ); + + if (isLoading) { + return null; + } + + if (!friends?.length) { + return ; + } + return (
- - You have 4 active friends - +
+ {groupingTypes.map((grouping) => { + let requestCount = 0; + if (grouping.value === 'requests') { + requestCount = receivedRequests.length; + } + + return ( + + ); + })} +
+ + {filteredFriends.length > 0 && ( +
+ {filteredFriends.map((friend) => ( + {}} + key={friend.userId} + onReload={() => { + pageProgressMessage.set('Reloading friends ..'); + loadFriends().finally(() => { + pageProgressMessage.set(''); + }); + }} + /> + ))} +
+ )} + + {filteredFriends.length === 0 && ( +
+ Empty Friends +

+ {selectedGrouping === 'active' && 'No friends yet'} + {selectedGrouping === 'sent' && 'No requests sent'} + {selectedGrouping === 'requests' && 'No requests received'} +

+

+ Invite your friends to join you on Roadmap +

+ +
+ )}
); }