Skip to content

Commit

Permalink
Join group by URL (Closes #55)
Browse files Browse the repository at this point in the history
  • Loading branch information
scastiel committed Jan 24, 2024
1 parent 7956156 commit 545cf75
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 37 deletions.
8 changes: 8 additions & 0 deletions src/app/groups/add-group-by-url-button-actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use server'

import { getGroup } from '@/lib/api'

export async function getGroupInfoAction(groupId: string) {
'use server'
return getGroup(groupId)
}
91 changes: 91 additions & 0 deletions src/app/groups/add-group-by-url-button.tsx
Original file line number Diff line number Diff line change
@@ -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>
)
}
21 changes: 1 addition & 20 deletions src/app/groups/page.tsx
Original file line number Diff line number Diff line change
@@ -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 />
}
68 changes: 51 additions & 17 deletions src/app/groups/recent-group-list.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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 =
Expand Down Expand Up @@ -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()
Expand All @@ -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>
Expand Down Expand Up @@ -132,7 +141,7 @@ export function RecentGroupList() {
</div>
</>
)}
</>
</GroupsPage>
)
}

Expand All @@ -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>
</>
)
}
29 changes: 29 additions & 0 deletions src/app/groups/recent-groups-page.tsx
Original file line number Diff line number Diff line change
@@ -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>
</>
)
}

0 comments on commit 545cf75

Please sign in to comment.