diff --git a/src/app/(platform)/_components/destination.tsx b/src/app/(platform)/_components/destination.tsx index 28d3745..613abab 100644 --- a/src/app/(platform)/_components/destination.tsx +++ b/src/app/(platform)/_components/destination.tsx @@ -691,6 +691,7 @@ export function DestinationCard( {String(props.type).charAt(0).toUpperCase() + String(props.type).slice(1)} + {props.tags && props.tags?.length > 0 ? props.tags.map((tag) => ( @@ -698,6 +699,9 @@ export function DestinationCard( )) : null} + + {props.workspace.emoji + " " + props.workspace.name} + diff --git a/src/app/(platform)/_components/list.tsx b/src/app/(platform)/_components/list.tsx index c1e294e..88879c2 100644 --- a/src/app/(platform)/_components/list.tsx +++ b/src/app/(platform)/_components/list.tsx @@ -149,6 +149,10 @@ export function ListCard(props: List) { )) : null} + + {props.workspace.emoji + " " + props.workspace.name} + + @@ -603,6 +607,9 @@ export function ListPage(props: { id: string }) { ))} ) : null} + + +
{data?.size && (
@@ -611,7 +618,7 @@ export function ListPage(props: { id: string }) {

•

- )} + )} {(data?.updatedAt && "Updated " + diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b567f86..c63f2a8 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -10,8 +10,9 @@ import PostHogPageView from "./PostHogPageView"; import { CSPostHogProvider } from "./providers"; export const metadata: Metadata = { - title: "Regreso | Dashboard", - description: "Regreso is an app that helps you find your way back.", + title: "Regreso | App Dashboard", + description: + "Regreso is an app that helps you find your way back. Never lose your digital trail again by effortlessly finding your way back to websites, articles, and resources.", icons: [ { rel: "icon", url: "/favicon.ico", sizes: "any" }, { rel: "icon", url: "/favicon.svg", type: "image/svg+xml" }, diff --git a/src/components/sidebar-left.tsx b/src/components/sidebar-left.tsx index 85a9681..f1c55a0 100644 --- a/src/components/sidebar-left.tsx +++ b/src/components/sidebar-left.tsx @@ -139,19 +139,28 @@ export function SidebarLeft({ ...props }: ComponentProps) { const [mode, setMode] = useState<"fav" | "rec">("rec"); const [oldMode, setOldMode] = useState<"fav" | "rec">("rec"); - const { data: recentLists = { items: [], count: 0 }, refetch } = + const { data: recentLists = { items: [], count: 0 }, refetchLists } = api.list.getMany.useQuery({ limit: 3, order: "DESC", tags: mode === "fav" ? ["favorite maps"] : undefined, }); + const { + data: recentWorkspaces = { items: [], count: 0 }, + refetch: refetchWorkspaces, + } = api.workspace.getMany.useQuery({ + limit: 3, + order: "DESC", + includeLists: true, + }); + useEffect(() => { if (mode !== oldMode) { - void refetch(); + void refetchLists(); setOldMode(mode); } - }, [mode, refetch, oldMode, setOldMode]); + }, [mode, refetchLists, oldMode, setOldMode]); return ( @@ -161,7 +170,7 @@ export function SidebarLeft({ ...props }: ComponentProps) { { return { @@ -176,7 +185,31 @@ export function SidebarLeft({ ...props }: ComponentProps) { /> - + { + return { + id: w.id, + name: w.name, + emoji: w.emoji, + { + return { + id: w.id, + name: w.name, + emoji: w.emoji, + pages: w.lists.map((list) => ({ + name: list.name, + url: "/map/" + list.id, + emoji: list.emoji ?? "❔", + })), + }; + })} + /> + + ], + }; + })} + /> diff --git a/src/server/api/routers/destination.ts b/src/server/api/routers/destination.ts index 958fad9..2677a2d 100644 --- a/src/server/api/routers/destination.ts +++ b/src/server/api/routers/destination.ts @@ -30,6 +30,7 @@ import { lists, listTags, tags, + workspaces, } from "~/server/db/schema"; export const destinationRouter = createTRPCRouter({ @@ -129,9 +130,11 @@ export const destinationRouter = createTRPCRouter({ const dests = await ctx.db .select({ destination: destinations, + workspace: workspaces, count: sql`count(*) over()`, }) .from(destinations) + .leftJoin(workspaces, eq(destinations.workspaceId, workspaces.id)) .leftJoin( destinationLists, listIds.length > 0 || tagNames.length > 0 @@ -191,7 +194,7 @@ export const destinationRouter = createTRPCRouter({ eq(destinations.userId, ctx.user.id), ), ) - .groupBy(destinations.id) + .groupBy(destinations.id, workspaces.id) .having( and( tagNames.length > 0 @@ -212,6 +215,7 @@ export const destinationRouter = createTRPCRouter({ ) .limit(input.limit) .offset(input.offset); + const destTags = await ctx.db .select() .from(destinationTags) @@ -226,7 +230,7 @@ export const destinationRouter = createTRPCRouter({ const returnDestinations = dests.map((dest) => { const destination = { id: dest.destination.id, - workspaceId: dest.destination.workspaceId, + workspace: dest.workspace, userId: dest.destination.userId, createdAt: dest.destination.createdAt, updatedAt: dest.destination.updatedAt, @@ -249,6 +253,7 @@ export const destinationRouter = createTRPCRouter({ }; return destination; }); + return { items: returnDestinations, count: @@ -379,6 +384,9 @@ export const destinationRouter = createTRPCRouter({ eq(destinations.id, input.id), eq(destinations.userId, ctx.user.id), ), + with: { + workspace: true, + }, }); if (!dest) { throw new TRPCError({ diff --git a/src/server/api/routers/list.ts b/src/server/api/routers/list.ts index 3b20843..1635aa5 100644 --- a/src/server/api/routers/list.ts +++ b/src/server/api/routers/list.ts @@ -20,6 +20,7 @@ import { lists, listTags, tags, + workspaces, } from "~/server/db/schema"; export const listRouter = createTRPCRouter({ @@ -122,6 +123,7 @@ export const listRouter = createTRPCRouter({ ), }) .from(lists) + .leftJoin(destinationLists, eq(lists.id, destinationLists.listId)) .leftJoin( destinations, @@ -139,6 +141,7 @@ export const listRouter = createTRPCRouter({ latestCreatedAt: sql`${stats.latestCreatedAt}`.as( "updated_at", ), + workspace: workspaces, }) .from(lists) .leftJoin(stats, eq(lists.id, stats.listId)) @@ -150,6 +153,7 @@ export const listRouter = createTRPCRouter({ tags, tagNames.length > 0 ? eq(listTags.tagId, tags.id) : sql`1 = 0`, ) + .rightJoin(workspaces, eq(lists.workspaceId, workspaces.id)) .where( and( and( @@ -168,6 +172,7 @@ export const listRouter = createTRPCRouter({ eq(lists.userId, ctx.user.id), ), ) + .groupBy( lists.id, lists.name, @@ -176,6 +181,7 @@ export const listRouter = createTRPCRouter({ lists.createdAt, stats.size, stats.latestCreatedAt, + workspaces.id, ) .orderBy( input.order === "ASC" @@ -209,6 +215,7 @@ export const listRouter = createTRPCRouter({ ); const returnLists: List[] = lsts.map((list) => { + delete list.list.workspaceId; return { tags: lstTags .filter((tag) => tag.list_tag.listId == list.list.id) @@ -236,6 +243,7 @@ export const listRouter = createTRPCRouter({ )?.[0] ?? null) : null : null, + workspace: list.workspace, }; }); if (!lsts || lsts.length === 0) { @@ -244,6 +252,7 @@ export const listRouter = createTRPCRouter({ message: "No lists found", }); } + return { items: returnLists, count: @@ -435,7 +444,6 @@ export const listRouter = createTRPCRouter({ emoji: lists.emoji, createdAt: lists.createdAt, userId: lists.userId, - workspaceId: lists.workspaceId, count: sql`count(*) over()`, size: sql`COUNT(${destinationLists}.id)`, updatedAt: sql`( @@ -447,8 +455,9 @@ export const listRouter = createTRPCRouter({ }) .from(lists) .leftJoin(destinationLists, eq(lists.id, destinationLists.listId)) + .leftJoin(workspaces, eq(lists.workspaceId, workspaces.id)) .where(and(eq(lists.id, input.id), eq(lists.userId, ctx.user.id))) - .groupBy(lists.id) + .groupBy(lists.id, workspaces.id) .limit(1); if (!lstData || lstData.length === 0 || !lstData[0]) { diff --git a/src/server/models.ts b/src/server/models.ts index 3a7c6a0..f12e30d 100644 --- a/src/server/models.ts +++ b/src/server/models.ts @@ -39,7 +39,7 @@ export interface Destination { tags?: { id: number; text: string }[]; updatedAt: Date | null; lists?: List[]; - workspaceId: number; + workspace: Workspace; } export interface List { @@ -52,7 +52,7 @@ export interface List { size?: number; updatedAt?: Date | null; tags?: { id: number; text: string }[]; - workspaceId: number; + workspace: Workspace; } export interface Workspace { @@ -64,6 +64,7 @@ export interface Workspace { createdAt: Date; destinationCount?: number; listCount?: number; + lists?: List[]; } export interface Tag { @@ -75,7 +76,7 @@ export interface Tag { userId: number; destinationCount?: number; listCount?: number; - workspaceId: number | null; + workspace: Workspace | null; createdAt: Date; updatedAt: Date | null; } @@ -175,6 +176,16 @@ export const tagFormSchema = z.object({ workspaceId: z.number(), }); +export const workspaceSchema = z.object({ + id: z.number(), + userId: z.number(), + createdAt: z.date(), + name: z.string(), + description: z.string().nullable(), + emoji: z.string().nullable(), + lists: z.array(z.any()).optional(), +}); + export const destinationSchema = z.object({ id: z.number(), userId: z.number(), @@ -186,7 +197,7 @@ export const destinationSchema = z.object({ location: z.string().nullable(), body: z.string().nullable(), attachments: z.array(z.any()).optional(), - workspaceId: z.number(), + workspace: workspaceSchema, }); export const listSchema = z.object({ @@ -198,19 +209,10 @@ export const listSchema = z.object({ size: z.number().optional(), name: z.string(), emoji: z.string().nullable(), - workspaceId: z.number(), + workspace: workspaceSchema, description: z.string().nullable(), }); -export const workspaceSchema = z.object({ - id: z.number(), - userId: z.number(), - createdAt: z.date(), - name: z.string(), - description: z.string().nullable(), - emoji: z.string().nullable(), -}); - export const tagSchema = z.object({ id: z.number(), userId: z.number(), @@ -280,6 +282,7 @@ export const workspaceSearchSchema = z.object({ order: z.enum(["ASC", "DESC"]).optional(), limit: z.number().max(30).optional().default(5), offset: z.number().optional().default(0), + includeLists: z.boolean().optional().default(false), }); export const tagSearchSchema = z.object({ diff --git a/src/server/user.ts b/src/server/user.ts index 594afca..ef2a96b 100644 --- a/src/server/user.ts +++ b/src/server/user.ts @@ -66,6 +66,7 @@ export async function createUser( .values({ userId: userRow[0]!.id, name: "Default Workspace", + emoji: "🧰", description: "This is your first workspace. Do something awesome with it!", })