Skip to content

Commit

Permalink
initial list implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
dinkelspiel committed May 28, 2024
1 parent d19dfe8 commit a307d40
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 42 deletions.
4 changes: 2 additions & 2 deletions app/(app)/dashboard/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ const Dashboard = ({
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-4">
<h2 className="text-2xl font-medium">
<h2 className="text-xl font-medium">
Highest rated media you haven’t completed
</h2>
<div className="grid grid-cols-3 gap-4">
Expand All @@ -211,7 +211,7 @@ const Dashboard = ({
</div> */}
</div>
<div className="flex flex-col gap-4">
<h2 className="text-2xl font-medium">
<h2 className="text-xl font-medium">
Most popular media you haven’t completed
</h2>
<div className="grid grid-cols-3 gap-4">
Expand Down
21 changes: 19 additions & 2 deletions app/(app)/users/[username]/lists/[listId]/addMedia.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ import UserEntryCard from '@/components/userEntryCard';
import { Entry, User, UserList, UserListEntry } from '@prisma/client';
import { ChevronDown, ChevronUp, Plus, X } from 'lucide-react';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { toast } from 'sonner';

const AddMedia = ({
userList,
userList: userListDefault,
user,
}: {
user: User;
userList: UserList & { entries: (UserListEntry & { entry: Entry })[] };
}) => {
const [userList, setUserList] = useState(userListDefault);
const router = useRouter();

const addEntryToList = async (entryId: number) => {
Expand All @@ -36,6 +38,20 @@ const AddMedia = ({
};

const moveEntry = async (entryId: number, order: number) => {
setUserList({
...userList,
entries: [
...userList.entries.filter(e => e.id !== entryId),
{
...userList.entries.find(e => e.id === entryId)!,
order:
order > userList.entries.find(e => e.id === entryId)!.order
? order + 0.5
: order - 0.5,
},
],
});

const response = await (
await fetch(`/api/user/lists/${userList.id}/entries/${entryId}`, {
method: 'PATCH',
Expand All @@ -59,6 +75,7 @@ const AddMedia = ({
.sort((a, b) => a.order - b.order)
.map(e => (
<UserEntryCard
key={e.id}
{...{
title: e.entry.originalTitle,
backgroundImage: e.entry.posterPath,
Expand Down Expand Up @@ -112,7 +129,7 @@ const AddMedia = ({
<Plus />
Add Media
</Button>
</AddLog>{' '}
</AddLog>
</>
);
};
Expand Down
34 changes: 31 additions & 3 deletions app/(app)/users/[username]/lists/[listId]/editableDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
'use client';
import React, { createRef, useEffect } from 'react';
import { UserList } from '@prisma/client';
import React, { createRef, useEffect, useState } from 'react';
import { toast } from 'sonner';

const EditableDescription = ({ description }: { description: string }) => {
const EditableDescription = ({ userList }: { userList: UserList }) => {
const [description, setDescription] = useState(userList.description);
const ref = createRef<HTMLTextAreaElement>();

useEffect(() => {
Expand All @@ -13,14 +16,39 @@ const EditableDescription = ({ description }: { description: string }) => {
ref.current.style.height = `${ref.current.scrollHeight}px`;
});

const updateDescription = async () => {
if (description === userList.description) {
return;
}

const response = await (
await fetch(`/api/user/lists/${userList.id}`, {
method: 'PATCH',
body: JSON.stringify({
description,
}),
})
).json();

if (response.error) {
toast.error(`Error updating list: ${response.error}`);
} else {
toast.success(response.message);
}
};

return (
<textarea
ref={ref}
onInput={e => {
(e.target as any).style.height = 'inherit';
(e.target as any).style.height = `${(e.target as any).scrollHeight}px`;
}}
defaultValue={description}
value={description}
onChange={e => setDescription(e.target.value)}
onBlur={() => {
updateDescription();
}}
className="h-max resize-none text-base text-gray-700"
/>
);
Expand Down
41 changes: 41 additions & 0 deletions app/(app)/users/[username]/lists/[listId]/editableName.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use client';
import { UserList } from '@prisma/client';
import React, { createRef, useEffect, useState } from 'react';
import { toast } from 'sonner';

const EditableName = ({ userList }: { userList: UserList }) => {
const [name, setName] = useState(userList.name);

const updateName = async () => {
if (name === userList.name) {
return;
}

const response = await (
await fetch(`/api/user/lists/${userList.id}`, {
method: 'PATCH',
body: JSON.stringify({
name,
}),
})
).json();

if (response.error) {
toast.error(`Error updating list: ${response.error}`);
} else {
toast.success(response.message);
}
};

return (
<input
value={name}
onChange={e => setName(e.target.value)}
onBlur={() => {
updateName();
}}
/>
);
};

export default EditableName;
11 changes: 6 additions & 5 deletions app/(app)/users/[username]/lists/[listId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Button } from '@/components/ui/button';
import { Plus, X } from 'lucide-react';
import EditableDescription from './editableDescription';
import AddMedia from './addMedia';
import EditableName from './editableName';

const Page = async ({
params,
Expand Down Expand Up @@ -80,7 +81,7 @@ const Page = async ({
<HeaderHeader>
<HeaderTitle>
{authUser && authUser?.id === targetUser.id && (
<input defaultValue={list.name} />
<EditableName userList={list} />
)}
{!(authUser && authUser?.id === targetUser.id) && list.name}
</HeaderTitle>
Expand All @@ -92,8 +93,8 @@ const Page = async ({
</HeaderDescription>
</HeaderHeader>
</Header>
<div className="mx-auto flex w-full flex-col-reverse gap-16 pb-8 pt-4 md:w-fit xl:grid xl:grid-cols-[1fr,250px] xl:gap-4">
<div className="grid w-full grid-cols-3 gap-4 px-4 ps-4 md:grid-cols-4 xl:w-[716px] xl:pe-4">
<div className="mx-auto flex w-full flex-col-reverse gap-16 pb-8 pt-4 md:w-fit min-[1330px]:grid min-[1330px]:grid-cols-[1fr,250px]">
<div className="grid w-full grid-cols-3 gap-4 px-4 ps-4 md:grid-cols-4 min-[1330px]:w-[716px] min-[1330px]:pe-4">
{!(authUser && authUser?.id === targetUser.id) &&
list.entries
.sort((a, b) => a.order - b.order)
Expand All @@ -112,9 +113,9 @@ const Page = async ({
<AddMedia userList={list} user={targetUser} />
)}
</div>
<div className="flex flex-col gap-6 px-4 xl:ps-0">
<div className="flex flex-col gap-6 px-4 min-[1330px]:px-0">
{authUser && authUser?.id === targetUser.id && (
<EditableDescription description={list.description} />
<EditableDescription userList={list} />
)}
{!(authUser && authUser?.id === targetUser.id) && (
<div className="h-max text-base text-gray-700">
Expand Down
4 changes: 4 additions & 0 deletions app/api/user/lists/[listId]/entries/[entryId]/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { validateSessionToken } from '@/server/auth/validateSession';
import prisma from '@/server/db';
import { normalizeOrderInList } from '@/server/user/list/normalizeOrder';
import z from 'zod';

export const PATCH = async (
Expand Down Expand Up @@ -34,6 +35,7 @@ export const PATCH = async (
const list = await prisma.userList.findUnique({
where: {
id: Number(params.listId),
userId: user.id,
},
include: {
entries: true,
Expand Down Expand Up @@ -106,6 +108,8 @@ export const PATCH = async (
);

await prisma.$transaction(updates);

await normalizeOrderInList(list);
}

return Response.json(
Expand Down
32 changes: 2 additions & 30 deletions app/api/user/lists/[listId]/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { validateSessionToken } from '@/server/auth/validateSession';
import prisma from '@/server/db';
import { normalizeOrderInList } from '@/server/user/list/normalizeOrder';
import { UserList } from '@prisma/client';
import { NextRequest } from 'next/server';
import z from 'zod';
Expand Down Expand Up @@ -124,6 +125,7 @@ export const PATCH = async (
const list = await prisma.userList.findUnique({
where: {
id: Number(params.listId),
userId: user.id,
},
include: {
entries: true,
Expand Down Expand Up @@ -158,33 +160,3 @@ export const PATCH = async (

return Response.json({ message: 'Updated list' }, { status: 200 });
};

/**
*
* @returns {number} Returns the largest order number in the list + 1
*/
const normalizeOrderInList = async (userList: UserList): Promise<number> => {
const listEntries = (
await prisma.userListEntry.findMany({
where: {
listId: userList.id,
},
})
).sort((a, b) => a.order - b.order);

let idx = 0;
for (const listEntry of listEntries) {
await prisma.userListEntry.update({
where: {
id: listEntry.id,
},
data: {
order: idx,
},
});

idx++;
}

return idx + 1;
};
35 changes: 35 additions & 0 deletions server/user/list/normalizeOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import prisma from '@/server/db';
import { UserList } from '@prisma/client';
import 'server-only';

/**
*
* @returns {number} Returns the largest order number in the list + 1
*/
export const normalizeOrderInList = async (
userList: UserList
): Promise<number> => {
const listEntries = (
await prisma.userListEntry.findMany({
where: {
listId: userList.id,
},
})
).sort((a, b) => a.order - b.order);

let idx = 0;
for (const listEntry of listEntries) {
await prisma.userListEntry.update({
where: {
id: listEntry.id,
},
data: {
order: idx,
},
});

idx++;
}

return idx + 1;
};

0 comments on commit a307d40

Please sign in to comment.