Skip to content

Commit

Permalink
update dashboard to new design
Browse files Browse the repository at this point in the history
  • Loading branch information
dinkelspiel committed May 23, 2024
1 parent 21cc7fc commit 7ecd341
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 33 deletions.
138 changes: 120 additions & 18 deletions app/(app)/dashboard/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import {
} from '@/components/header';
import UserEntryComponent from '../../../components/userEntry';
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Entry, User, UserEntry, UserEntryStatus } from '@prisma/client';
import {
Entry,
User,
UserEntry,
UserEntryStatus,
UserList,
} from '@prisma/client';
import {
AArrowDown,
Command,
Expand Down Expand Up @@ -40,6 +46,10 @@ import { FilterStyle, useDashboardStore } from './state';
import useSwr from 'swr';
import fetcher from '@/client/fetcher';
import ModifyUserEntry from '@/components/modifyUserEntry';
import { UserEntryCardObject } from '@/components/userEntryCard';
import { useMediaQuery } from 'usehooks-ts';
import { toast } from 'sonner';
import { Drawer, DrawerContent } from '@/components/ui/drawer';

const Dashboard = ({
userEntries: originalUserEntries,
Expand All @@ -57,6 +67,9 @@ const Dashboard = ({
userEntries,
setUserEntries,
setUserEntry,

selectedUserEntry,
setSelectedUserEntry,
} = useDashboardStore();

useEffect(() => {
Expand Down Expand Up @@ -100,11 +113,100 @@ const Dashboard = ({
};
}, []);

// Lists

useEffect(() => {
if (selectedUserEntry === undefined) {
return;
}

fetchUserListsWithEntry(selectedUserEntry ?? 0);
}, [selectedUserEntry]);

const [listsWithUserEntry, setListsWithUserEntry] = useState<UserList[]>([]);
const [userLists, setUserLists] = useState<UserList[]>([]);
const fetchUserLists = async () => {
const listsResponse = await (await fetch(`/api/user/lists`)).json();

if (listsResponse.error) {
toast.error(`Error fetching userLists: ${listsResponse.error}`);
} else {
setUserLists(listsResponse);
}
};

const fetchUserListsWithEntry = async (userEntryId: number) => {
const entryListsResponse = await (
await fetch(`/api/user/entries/${userEntryId}/lists`)
).json();

if (entryListsResponse.error) {
toast.error(
`Error fetching entry userLists: ${entryListsResponse.error}`
);
} else {
setListsWithUserEntry(entryListsResponse);
}

fetchUserLists();
};

const InformationView = () => {
if (selectedUserEntry) {
return (
<ModifyUserEntry
userEntry={userEntries.find(e => e.id == selectedUserEntry)!}
setOpen={() => {
setSelectedUserEntry(undefined);
}}
setUserEntry={setUserEntry}
userLists={userLists ?? []}
userListsWithEntry={listsWithUserEntry}
refetchUserLists={async () => {
fetchUserLists();
fetchUserListsWithEntry(selectedUserEntry);
}}
/>
);
} else {
return (
<>
<h3>Most popular media today</h3>
</>
);
}
};

// Mobile

const isAbove2xl = useMediaQuery('(min-width: 1536px)');
const [informationViewOpen, setInformationViewOpenValue] = useState(false);

const setInformationViewOpen = (open: boolean) => {
if (!open) {
setSelectedUserEntry(undefined);
}

setInformationViewOpenValue(open);
};

useEffect(() => {
if (selectedUserEntry === undefined) {
return;
}

if (isAbove2xl) {
return;
}

setInformationViewOpen(true);
}, [selectedUserEntry]);

return (
<>
<Header className="col-span-2">
<HeaderHeader>
<HeaderTitle>My Media</HeaderTitle>
<HeaderTitle>My Media {isAbove2xl ? 'true' : 'false'}</HeaderTitle>
<HeaderDescription>
Search through your entire media catalogue
</HeaderDescription>
Expand Down Expand Up @@ -190,8 +292,8 @@ const Dashboard = ({
</Popover>
</HeaderContent>
</Header>
<div className="grid justify-center p-4">
<div className="grid w-fit grid-cols-3 gap-4 min-[700px]:grid-cols-4 min-[1100px]:grid-cols-5 min-[1300px]:grid-cols-6 min-[1500px]:grid-cols-7 min-[1600px]:grid-cols-8 min-[1700px]:grid-cols-8">
<div className="col-span-2 grid justify-center p-4 2xl:col-span-1">
<div className="grid w-fit grid-cols-3 gap-4 min-[700px]:grid-cols-4 min-[1100px]:grid-cols-5 min-[1300px]:grid-cols-6 min-[1500px]:grid-cols-7 2xl:grid-cols-4 min-[1600px]:grid-cols-5 min-[1800px]:grid-cols-6 min-[2000px]:grid-cols-7 min-[2200px]:grid-cols-8">
{userEntries
.sort((a, b) => {
switch (filterStyle) {
Expand Down Expand Up @@ -259,27 +361,27 @@ const Dashboard = ({
}

return (
<UserEntryComponent
userEntry={userEntry}
setUserEntry={setUserEntry}
<UserEntryCardObject
key={userEntry.id}
userEntry={userEntry}
onClick={() => {
setSelectedUserEntry(userEntry.id);
setListsWithUserEntry([]);
fetchUserListsWithEntry(userEntry.id);
}}
/>
);
})}
</div>
</div>
<div className="sticky top-[80px] h-[calc(100dvh-81px)] bg-[#F5F5F5] p-4 shadow-[inset_0_0px_8px_0_rgb(0_0_0_/_0.02)] shadow-gray-300">
{userEntries[0] && (
<ModifyUserEntry
userEntry={userEntries[0]!}
setOpen={() => []}
setUserEntry={setUserEntry}
userLists={[]}
userListsWithEntry={[]}
refetchUserLists={async () => {}}
/>
)}
<div className="sticky top-[81px] hidden h-[calc(100dvh-81px)] bg-[#F5F5F5] p-4 shadow-[inset_0_0px_8px_0_rgb(0_0_0_/_0.02)] shadow-gray-300 2xl:block">
<InformationView />
</div>
<Drawer open={informationViewOpen} onOpenChange={setInformationViewOpen}>
<DrawerContent className="top-[50px] mt-0 p-6">
<InformationView />
</DrawerContent>
</Drawer>
</>
);
};
Expand Down
10 changes: 10 additions & 0 deletions app/(app)/dashboard/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ type DashboardStore = {
userEntries: ExtendedUserEntry[];
setUserEntries: (userEntries: ExtendedUserEntry[]) => void;
setUserEntry: (userEntry: ExtendedUserEntry) => void;

selectedUserEntry: number | undefined;
setSelectedUserEntry: (userEntryId: number | undefined) => void;
};

export const useDashboardStore = create<DashboardStore>(set => ({
Expand All @@ -36,4 +39,11 @@ export const useDashboardStore = create<DashboardStore>(set => ({
userEntry,
],
})),

selectedUserEntry: undefined,
setSelectedUserEntry: (userEntryId: number | undefined) =>
set(state => ({
selectedUserEntry:
userEntryId === state.selectedUserEntry ? undefined : userEntryId,
})),
}));
4 changes: 3 additions & 1 deletion app/(app)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ const Layout = async ({ children }: { children: ReactNode }) => {
</SidebarFooter>
</Sidebar>

<main className="grid grid-cols-[1fr,600px]">{children}</main>
<main className="grid grid-cols-1 lg:grid-cols-[1fr,600px]">
{children}
</main>
<Toaster />
</SidebarLayout>
);
Expand Down
2 changes: 1 addition & 1 deletion components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const Header = ({
return (
<div
className={cn(
'sticky top-0 z-10 flex flex-row border-b border-b-gray-200 bg-white px-4 py-3',
'sticky top-[75px] z-10 flex flex-row border-b border-b-gray-200 bg-white px-4 py-3 lg:top-0',
className
)}
{...props}
Expand Down
17 changes: 12 additions & 5 deletions components/modifyUserEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,13 @@ const ModifyUserEntry = ({

const [addListsOpen, setAddListsOpen] = useState(false);

useEffect(() => {
setNotes(userEntry.notes);
setRating(userEntry.rating);
}, [userEntry]);

useEffect(() => {
if (state.message) {
setOpen(false);
setUserEntry({ ...userEntry, notes, rating });
toast.success(state.message);
}
Expand Down Expand Up @@ -177,14 +181,14 @@ const ModifyUserEntry = ({
};

const Header = () => (
<div className="grid w-fit grid-cols-[max-content,1fr] gap-4 pb-4 pt-4 lg:pt-0">
<div className="grid w-full grid-cols-[max-content,1fr] gap-4 pb-4 pt-4 lg:pt-0">
<img
src={userEntry.entry.posterPath}
className="aspect-[2/3] w-[100px] rounded-lg shadow-md"
/>
<div className="flex flex-col gap-2">
<div className="flex items-end gap-2">
<div className="text-lg font-semibold tracking-tight lg:pt-0 xl:w-max">
<div className="text-lg font-semibold tracking-tight lg:pt-0">
{userEntry.entry.originalTitle}
</div>
<div className="pb-[2px] text-sm text-muted-foreground">
Expand All @@ -208,7 +212,7 @@ const ModifyUserEntry = ({

if (userEntry.watchedAt !== null) {
return (
<div className="grid h-full w-full grow grid-rows-[max-content,max-content,1fr,max-content]">
<div className="grid h-full grow grid-rows-[max-content,max-content,1fr,max-content]">
<Header />
<div className="flex flex-row items-center gap-3 border-b border-b-gray-200 py-3 text-sm">
<div className="w-max text-muted-foreground">Rating</div>
Expand Down Expand Up @@ -269,7 +273,10 @@ const ModifyUserEntry = ({
{userLists.length !== 0 && (
<CommandGroup>
{userLists.map(list => (
<div className="flex justify-between gap-1">
<div
className="flex justify-between gap-1"
key={list.id}
>
<CommandItem
key={list.id}
value={list.name}
Expand Down
2 changes: 1 addition & 1 deletion components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const Sidebar = ({
{...props}
aria-label="Sidebar"
>
<div className="flex h-[75px] flex-col justify-center overflow-y-auto border-b border-e border-gray-300 bg-neutral-100 px-3 py-4 shadow-md shadow-gray-300 dark:border-slate-700 dark:bg-slate-900 lg:h-full lg:justify-start lg:border-b-0">
<div className="flex h-[75px] flex-col justify-center overflow-y-auto border-b border-e border-gray-300 bg-neutral-100 px-3 py-4 shadow-gray-200 dark:border-slate-700 dark:bg-slate-900 lg:h-full lg:justify-start lg:border-b-0 lg:shadow-md lg:shadow-gray-300">
<SidebarHeader {...headerProps}>
{header}
<button className="flex justify-end px-2 lg:hidden">
Expand Down
43 changes: 43 additions & 0 deletions components/ui/resizable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { DragHandleDots2Icon } from "@radix-ui/react-icons"
import * as ResizablePrimitive from "react-resizable-panels"

import { cn } from "@/lib/utils"

const ResizablePanelGroup = ({
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
<ResizablePrimitive.PanelGroup
className={cn(
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
className
)}
{...props}
/>
)

const ResizablePanel = ResizablePrimitive.Panel

const ResizableHandle = ({
withHandle,
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
withHandle?: boolean
}) => (
<ResizablePrimitive.PanelResizeHandle
className={cn(
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className
)}
{...props}
>
{withHandle && (
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
<DragHandleDots2Icon className="h-2.5 w-2.5" />
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
)

export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
Loading

0 comments on commit 7ecd341

Please sign in to comment.