Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Spaces #2

Merged
merged 15 commits into from
Dec 6, 2023
45 changes: 45 additions & 0 deletions app/actions/list.action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use server';

import { revalidateTag } from 'next/cache';
import { redirect } from 'next/navigation';
import { z } from 'zod';

import { auth } from '@/lib/auth';
import { prisma } from '@/lib/prisma';

const schema = z.object({
name: z.string(),
spaceId: z.string()
});

export const addList = async (formData: FormData) => {
const { name, spaceId } = schema.parse({
name: formData.get('name'),
spaceId: formData.get('spaceId')
});

const session = await auth();

const newList = await prisma.list.create({
data: {
name,
Space: {
connect: {
id: spaceId
}
},
creator: {
connect: {
id: session?.user.id
}
}
},
select: {
id: true
}
});

revalidateTag(`/spaces/${spaceId}`);

redirect(`/spaces/${spaceId}/lists/${newList.id}`);
};
35 changes: 35 additions & 0 deletions app/actions/space.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use server';

import { revalidateTag } from 'next/cache';
import { redirect } from 'next/navigation';
import { z } from 'zod';

import { auth } from '@/lib/auth';
import { prisma } from '@/lib/prisma';

const schema = z.object({
name: z.string()
});

export const addSpace = async (formData: FormData) => {
const parsed = schema.parse({
name: formData.get('name')
});

const session = await auth();

const space = await prisma.space.create({
data: {
name: parsed.name,
creator: {
connect: {
id: session?.user.id
}
}
}
});

revalidateTag('/spaces');

redirect(`/spaces/${space.id}`);
};
2 changes: 1 addition & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export default function Home() {
return (
<main>
<h1>main content</h1>
<h1>hello</h1>
</main>
);
}
29 changes: 29 additions & 0 deletions app/spaces/[spaceId]/lists/[listId]/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use client';

import Link from 'next/link';
import { useParams } from 'next/navigation';

import { SpaceItemParams } from '../../page';

export default function NotFound() {
const params = useParams<SpaceItemParams>();

return (
<div>
<h3 className="text-3xl">Oops Your List was not found</h3>

<div className="flex flex-col gap-2 mt-4">
<p>
Go back to{' '}
<Link href={`/spaces/${params.spaceId}`} className="underline">
Your Lists
</Link>{' '}
or{' '}
<Link href="/" className="underline">
Home Page
</Link>
</p>
</div>
</div>
);
}
24 changes: 24 additions & 0 deletions app/spaces/[spaceId]/lists/[listId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { notFound } from 'next/navigation';

import { prisma } from '@/lib/prisma';

import { SpaceItemParams } from '../../page';

type ListItemParams = SpaceItemParams & {
listId: string;
};
export default async function List({ params }: { params: ListItemParams }) {
const list = await prisma.list.findUnique({
where: { id: params.listId }
});

if (!list) {
notFound();
}

return (
<div>
<h1>{params.spaceId}</h1>
</div>
);
}
25 changes: 25 additions & 0 deletions app/spaces/[spaceId]/lists/add/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { addList } from '@/app/actions/list.action';
import { FormField } from '@/components/formField';
import { Button } from '@/components/ui/button';

export default function AddList({
params: { spaceId }
}: {
params: { spaceId: string };
}) {
return (
<div>
<form action={addList}>
<FormField type="text" label="Name" name="name" />
<FormField
hidden
type="text"
name="spaceId"
defaultValue={spaceId}
readOnly
/>
<Button className="w-full mt-4">Submit</Button>
</form>
</div>
);
}
22 changes: 22 additions & 0 deletions app/spaces/[spaceId]/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Link from 'next/link';

export default function NotFound() {
return (
<div>
<h3 className="text-3xl">Oops Your Space was not found</h3>

<div className="flex flex-col gap-2 mt-4">
<p>
Go back to{' '}
<Link href="/spaces" className="underline">
Your Spaces
</Link>{' '}
or{' '}
<Link href="/" className="underline">
Home Page
</Link>
</p>
</div>
</div>
);
}
58 changes: 58 additions & 0 deletions app/spaces/[spaceId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Link from 'next/link';
import { notFound } from 'next/navigation';

import { prisma } from '@/lib/prisma';

export type SpaceItemParams = { spaceId: string };

export default async function SingleSpace({
params: { spaceId: paramsSpaceId }
}: {
params: SpaceItemParams;
}) {
const space = await prisma.space.findUnique({
where: { id: paramsSpaceId },
include: { Lists: true }
});

if (!space) {
notFound();
}

return (
<section>
<div className="flex gap-4 mb-4 mx-4 items-center justify-start">
<h2 className="text-3xl border max-w-fit px-4 py-2 rounded-2xl bg-primary text-primary-foreground">
<Link href={`/spaces/${space.id}`}>☀︎ {space.name}</Link>
</h2>
<Link
href={`/spaces/${space.id}/lists/add`}
className="text-3xl border px-4 py-2 rounded-2xl"
>
+
</Link>
</div>
{!space.Lists.length ? (
<div>
<h2 className="text-2xl">No List was Found</h2>
</div>
) : (
<ul className="flex flex-wrap gap-2">
{space.Lists.map((list) => (
<li
key={list.id}
className="text-xl text-center min-w-[200px] p-2 rounded-lg border"
>
<Link
href={`/spaces/${space.id}/lists/${list.id}`}
className="block"
>
{list.name}
</Link>
</li>
))}
</ul>
)}
</section>
);
}
17 changes: 17 additions & 0 deletions app/spaces/add/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { addSpace } from '@/app/actions/space.actions';
import { FormField } from '@/components/formField';
import { Button } from '@/components/ui/button';

export default async function NewSpace() {
return (
<div>
<h2>ADD NEW SPACE</h2>

<form action={addSpace}>
<FormField type="text" label="Name" name="name" />
{/* <FormField type="text" name="userId" hidden readOnly defaultValue={session?.user.} /> */}
<Button className="w-full mt-4">Submit</Button>
</form>
</div>
);
}
62 changes: 62 additions & 0 deletions app/spaces/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import Link from 'next/link';
import { redirect } from 'next/navigation';

import { auth } from '@/lib/auth';
import { prisma } from '@/lib/prisma';

export default async function Spaces() {
const session = await auth();

const id = session?.user?.id;

if (!id) {
redirect('/');
}

const spaces = await prisma.space.findMany({
where: {
creator: {
id
}
}
});

console.log(spaces);

return (
<main>
<header className="mb-8 flex gap-4">
<h2 className="text-2xl underline">
<Link href={`/spaces`}>Your Spaces</Link>
</h2>

<Link
href={`/spaces/add`}
className="text-xl text-center border rounded-lg min-w-[50px]"
>
+
</Link>
</header>
<div className="flex">
{spaces.length ? (
<section>
<ul className="flex flex-wrap gap-2">
{spaces.map((sp) => (
<li
key={sp.id}
className="text-xl text-center min-w-[200px] p-2 rounded-lg border"
>
<Link href={`/spaces/${sp.id}`} className="block">
{sp.name}
</Link>
</li>
))}
</ul>
</section>
) : (
<section>no space was found</section>
)}
</div>
</main>
);
}
2 changes: 1 addition & 1 deletion components/Anchor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { RouteType } from 'next/dist/lib/load-custom-routes';
import Link, { LinkProps } from 'next/link';

export function Anchor(props: PropsWithChildren<LinkProps<RouteType>>) {
return <Link {...props} className="text-lg w-full" />;
return <Link {...props} className="text-sm w-full" />;
}
3 changes: 2 additions & 1 deletion components/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ export async function Nav() {
const session = await auth();

return (
<nav className="fixed bottom-0 w-full justify-end items-center flex px-4 py-2 border">
<nav className="fixed bottom-0 w-full justify-end items-center flex px-4 py-2 border gap-3">
{/* TODO move to general place */}
{/* <AddExpense deviceType={deviceType || 'desktop'} /> */}

<UserAccount session={session} />
</nav>
);
Expand Down
9 changes: 8 additions & 1 deletion components/UserAccount/UserAccount.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import Image from 'next/image';
import Link from 'next/link';
import { Session } from 'next-auth';

import { GoogleSignIn, Logout, WebAuthn } from './AuthComponents';
Expand Down Expand Up @@ -38,8 +39,14 @@ export function UserAccount({ session }: Props) {
</DropdownMenuTrigger>
{session?.user ? (
<DropdownMenuContent>
<DropdownMenuLabel>{session.user.name}</DropdownMenuLabel>
<DropdownMenuLabel>
<Link href="/">{session.user.name}</Link>
</DropdownMenuLabel>
<DropdownMenuGroup>
<DropdownMenuItem>
<Link href="/spaces">Spaces</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>
<Logout />
</DropdownMenuItem>
Expand Down
7 changes: 6 additions & 1 deletion components/formField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ type InputProps = InputHTMLAttributes<HTMLInputElement> & {

export function FormField({ name, id, label, ...restInputProps }: InputProps) {
return (
<div className="mb-3 flex flex-col items-start">
<div
className={`mb-3 flex flex-col items-start ${
restInputProps.hidden ? 'hidden' : ''
}`}
hidden={restInputProps.hidden}
>
<Label htmlFor={id || name}>{label}</Label>
<Input id={id || name} name={name} {...restInputProps} />
</div>
Expand Down
Loading