diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/app/groups/add-group-by-url-button-actions.ts | 8 | ||||
| -rw-r--r-- | src/app/groups/add-group-by-url-button.tsx | 91 | ||||
| -rw-r--r-- | src/app/groups/page.tsx | 21 | ||||
| -rw-r--r-- | src/app/groups/recent-group-list.tsx | 68 | ||||
| -rw-r--r-- | src/app/groups/recent-groups-page.tsx | 29 |
5 files changed, 180 insertions, 37 deletions
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 0000000..b6c5147 --- /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 0000000..a33f5eb --- /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 ( + <Popover open={open} onOpenChange={setOpen}> + <PopoverTrigger asChild> + <Button variant="secondary"> + {/* <Plus className="w-4 h-4 mr-2" /> */} + <>Add by URL</> + </Button> + </PopoverTrigger> + <PopoverContent + align={isDesktop ? 'end' : 'start'} + className="[&_p]:text-sm flex flex-col gap-3" + > + <h3 className="font-bold">Add a group by URL</h3> + <p> + If a group was shared with you, you can paste its URL here to add it + to your list. + </p> + <form + className="flex gap-2" + onSubmit={async (event) => { + 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) + } + }} + > + <Input + type="url" + required + placeholder="https://spliit.app/..." + className="flex-1 text-base" + value={url} + disabled={pending} + onChange={(event) => { + setUrl(event.target.value) + setError(false) + }} + /> + <Button size="icon" type="submit" disabled={pending}> + {pending ? ( + <Loader2 className="w-4 h-4 animate-spin" /> + ) : ( + <Plus className="w-4 h-4" /> + )} + </Button> + </form> + {error && ( + <p className="text-destructive"> + Oops, we are not able to find the group from the URL you provided… + </p> + )} + </PopoverContent> + </Popover> + ) +} diff --git a/src/app/groups/page.tsx b/src/app/groups/page.tsx index 967c6b7..4366ec5 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 ( - <> - <div className="flex justify-between items-center gap-4"> - <h1 className="font-bold text-2xl"> - <Link href="/groups">My groups</Link> - </h1> - <Button asChild size="icon"> - <Link href="/groups/create"> - <Plus className="w-4 h-4" /> - </Link> - </Button> - </div> - <div> - <RecentGroupList /> - </div> - </> - ) + return <RecentGroupList /> } diff --git a/src/app/groups/recent-group-list.tsx b/src/app/groups/recent-group-list.tsx index 5f41fdb..9ad6f56 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<RecentGroupsState>({ 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 ( - <p> - <Loader2 className="w-4 m-4 mr-2 inline animate-spin" /> Loading recent - groups… - </p> + <GroupsPage reload={loadGroups}> + <p> + <Loader2 className="w-4 m-4 mr-2 inline animate-spin" /> Loading + recent groups… + </p> + </GroupsPage> ) } if (state.groups.length === 0) { return ( - <div className="text-sm space-y-2"> - <p>You have not visited any group recently.</p> - <p> - <Button variant="link" asChild className="-m-4"> - <Link href={`/groups/create`}>Create one</Link> - </Button>{' '} - or ask a friend to send you the link to an existing one. - </p> - </div> + <GroupsPage reload={loadGroups}> + <div className="text-sm space-y-2"> + <p>You have not visited any group recently.</p> + <p> + <Button variant="link" asChild className="-m-4"> + <Link href={`/groups/create`}>Create one</Link> + </Button>{' '} + or ask a friend to send you the link to an existing one. + </p> + </div> + </GroupsPage> ) } const { starredGroupInfo, groupInfo, archivedGroupInfo } = sortGroups(state) return ( - <> + <GroupsPage reload={loadGroups}> {starredGroupInfo.length > 0 && ( <> <h2 className="mb-2">Starred groups</h2> @@ -132,7 +141,7 @@ export function RecentGroupList() { </div> </> )} - </> + </GroupsPage> ) } @@ -158,3 +167,28 @@ function GroupList({ </ul> ) } + +function GroupsPage({ + children, + reload, +}: PropsWithChildren<{ reload: () => void }>) { + return ( + <> + <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-2"> + <h1 className="font-bold text-2xl flex-1"> + <Link href="/groups">My groups</Link> + </h1> + <div className="flex gap-2"> + <AddGroupByUrlButton reload={reload} /> + <Button asChild> + <Link href="/groups/create"> + {/* <Plus className="w-4 h-4 mr-2" /> */} + <>Create</> + </Link> + </Button> + </div> + </div> + <div>{children}</div> + </> + ) +} diff --git a/src/app/groups/recent-groups-page.tsx b/src/app/groups/recent-groups-page.tsx new file mode 100644 index 0000000..36874b0 --- /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 ( + <> + <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-2"> + <h1 className="font-bold text-2xl flex-1"> + <Link href="/groups">My groups</Link> + </h1> + <div className="flex gap-2"> + <AddGroupByUrlButton reload={() => {}} /> + <Button asChild> + <Link href="/groups/create"> + {/* <Plus className="w-4 h-4 mr-2" /> */} + <>Create</> + </Link> + </Button> + </div> + </div> + <div> + <RecentGroupList /> + </div> + </> + ) +} |
