From 545cf75e9993f4dbc0653512d01b198f111998bf Mon Sep 17 00:00:00 2001 From: Sebastien Castiel Date: Wed, 24 Jan 2024 11:12:55 -0500 Subject: [PATCH] Join group by URL (Closes #55) --- .../groups/add-group-by-url-button-actions.ts | 8 ++ src/app/groups/add-group-by-url-button.tsx | 91 +++++++++++++++++++ src/app/groups/page.tsx | 21 +---- src/app/groups/recent-group-list.tsx | 68 ++++++++++---- src/app/groups/recent-groups-page.tsx | 29 ++++++ 5 files changed, 180 insertions(+), 37 deletions(-) create mode 100644 src/app/groups/add-group-by-url-button-actions.ts create mode 100644 src/app/groups/add-group-by-url-button.tsx create mode 100644 src/app/groups/recent-groups-page.tsx diff --git a/src/app/groups/add-group-by-url-button-actions.ts b/src/app/groups/add-group-by-url-button-actions.ts new file mode 100644 index 00000000..b6c51474 --- /dev/null +++ b/src/app/groups/add-group-by-url-button-actions.ts @@ -0,0 +1,8 @@ +'use server' + +import { getGroup } from '@/lib/api' + +export async function getGroupInfoAction(groupId: string) { + 'use server' + return getGroup(groupId) +} diff --git a/src/app/groups/add-group-by-url-button.tsx b/src/app/groups/add-group-by-url-button.tsx new file mode 100644 index 00000000..a33f5ebe --- /dev/null +++ b/src/app/groups/add-group-by-url-button.tsx @@ -0,0 +1,91 @@ +import { getGroupInfoAction } from '@/app/groups/add-group-by-url-button-actions' +import { saveRecentGroup } from '@/app/groups/recent-groups-helpers' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover' +import { useMediaQuery } from '@/lib/hooks' +import { Loader2, Plus } from 'lucide-react' +import { useState } from 'react' + +type Props = { + reload: () => void +} + +export function AddGroupByUrlButton({ reload }: Props) { + const isDesktop = useMediaQuery('(min-width: 640px)') + const [url, setUrl] = useState('') + const [error, setError] = useState(false) + const [open, setOpen] = useState(false) + const [pending, setPending] = useState(false) + + return ( + + + + + +

Add a group by URL

+

+ If a group was shared with you, you can paste its URL here to add it + to your list. +

+
{ + event.preventDefault() + const [, groupId] = + url.match( + new RegExp(`${window.location.origin}/groups/([^/]+)`), + ) ?? [] + setPending(true) + const group = groupId ? await getGroupInfoAction(groupId) : null + setPending(false) + if (!group) { + setError(true) + } else { + saveRecentGroup({ id: group.id, name: group.name }) + reload() + setUrl('') + setOpen(false) + } + }} + > + { + setUrl(event.target.value) + setError(false) + }} + /> + +
+ {error && ( +

+ Oops, we are not able to find the group from the URL you provided… +

+ )} +
+
+ ) +} diff --git a/src/app/groups/page.tsx b/src/app/groups/page.tsx index 967c6b7b..4366ec51 100644 --- a/src/app/groups/page.tsx +++ b/src/app/groups/page.tsx @@ -1,29 +1,10 @@ import { RecentGroupList } from '@/app/groups/recent-group-list' -import { Button } from '@/components/ui/button' -import { Plus } from 'lucide-react' import { Metadata } from 'next' -import Link from 'next/link' export const metadata: Metadata = { title: 'Recently visited groups', } export default async function GroupsPage() { - return ( - <> -
-

- My groups -

- -
-
- -
- - ) + return } diff --git a/src/app/groups/recent-group-list.tsx b/src/app/groups/recent-group-list.tsx index 5f41fdbd..9ad6f562 100644 --- a/src/app/groups/recent-group-list.tsx +++ b/src/app/groups/recent-group-list.tsx @@ -1,5 +1,6 @@ 'use client' import { getGroupsAction } from '@/app/groups/actions' +import { AddGroupByUrlButton } from '@/app/groups/add-group-by-url-button' import { RecentGroups, getArchivedGroups, @@ -10,7 +11,7 @@ import { Button } from '@/components/ui/button' import { getGroups } from '@/lib/api' import { Loader2 } from 'lucide-react' import Link from 'next/link' -import { SetStateAction, useEffect, useState } from 'react' +import { PropsWithChildren, SetStateAction, useEffect, useState } from 'react' import { RecentGroupListCard } from './recent-group-list-card' export type RecentGroupsState = @@ -54,7 +55,7 @@ function sortGroups( export function RecentGroupList() { const [state, setState] = useState({ status: 'pending' }) - useEffect(() => { + function loadGroups() { const groupsInStorage = getRecentGroups() const starredGroups = getStarredGroups() const archivedGroups = getArchivedGroups() @@ -73,35 +74,43 @@ export function RecentGroupList() { archivedGroups, }) }) + } + + useEffect(() => { + loadGroups() }, []) if (state.status === 'pending') { return ( -

- Loading recent - groups… -

+ +

+ Loading + recent groups… +

+
) } if (state.groups.length === 0) { return ( -
-

You have not visited any group recently.

-

- {' '} - or ask a friend to send you the link to an existing one. -

-
+ +
+

You have not visited any group recently.

+

+ {' '} + or ask a friend to send you the link to an existing one. +

+
+
) } const { starredGroupInfo, groupInfo, archivedGroupInfo } = sortGroups(state) return ( - <> + {starredGroupInfo.length > 0 && ( <>

Starred groups

@@ -132,7 +141,7 @@ export function RecentGroupList() { )} - +
) } @@ -158,3 +167,28 @@ function GroupList({ ) } + +function GroupsPage({ + children, + reload, +}: PropsWithChildren<{ reload: () => void }>) { + return ( + <> +
+

+ My groups +

+
+ + +
+
+
{children}
+ + ) +} diff --git a/src/app/groups/recent-groups-page.tsx b/src/app/groups/recent-groups-page.tsx new file mode 100644 index 00000000..36874b0d --- /dev/null +++ b/src/app/groups/recent-groups-page.tsx @@ -0,0 +1,29 @@ +'use client' +import { AddGroupByUrlButton } from '@/app/groups/add-group-by-url-button' +import { RecentGroupList } from '@/app/groups/recent-group-list' +import { Button } from '@/components/ui/button' +import Link from 'next/link' + +export function RecentGroupsPage() { + return ( + <> +
+

+ My groups +

+
+ {}} /> + +
+
+
+ +
+ + ) +}