-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Added] site switch feature in navigation
- Loading branch information
1 parent
2af4b7b
commit 64b6c52
Showing
5 changed files
with
227 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { getSession } from "@/lib/auth"; | ||
import prisma from "@/lib/prisma"; | ||
import { NextResponse } from "next/server"; | ||
|
||
export async function GET(req: Request) { | ||
const session = await getSession(); | ||
if (!session) { | ||
return { | ||
status: 401, | ||
body: { | ||
message: "Unauthorized", | ||
}, | ||
}; | ||
} | ||
// const {} = req.json(); | ||
const sites = await prisma.site.findMany({ | ||
where: { | ||
user: { | ||
id: session?.user.id as string, | ||
}, | ||
}, | ||
orderBy: { | ||
createdAt: "asc", | ||
}, | ||
// ...(limit ? { take: limit } : {}), | ||
}); | ||
return NextResponse.json({ | ||
result:sites, | ||
status:"success" | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { ReactNode } from "react"; | ||
|
||
export default function SiteLayout({ children }: { children: ReactNode }) { | ||
return ( | ||
<div className="flex max-w-screen-xl flex-col space-y-12 p-8"> | ||
<div className="flex flex-col space-y-6">{children}</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import CreatePostButton from "@/components/create-post-button"; | ||
import Posts from "@/components/posts"; | ||
import { getSession } from "@/lib/auth"; | ||
import prisma from "@/lib/prisma"; | ||
import { notFound, redirect } from "next/navigation"; | ||
import React from "react"; | ||
|
||
export default async function SitePage({ | ||
params, | ||
}: { | ||
params: { siteId: string }; | ||
}) { | ||
const session = await getSession(); | ||
if (!session) { | ||
redirect("/login"); | ||
} | ||
const data = await prisma.site.findUnique({ | ||
where: { | ||
id: params.siteId, | ||
}, | ||
}); | ||
|
||
if (!data || data.userId !== session.user.id) { | ||
notFound(); | ||
} | ||
|
||
const url = `${data.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`; | ||
|
||
return ( | ||
<> | ||
<div className="flex flex-col items-center justify-between space-y-4 sm:flex-row sm:space-y-0"> | ||
<div className="flex flex-col items-center space-y-2 sm:flex-row sm:space-x-4 sm:space-y-0"> | ||
<h1 className="w-60 truncate font-cal text-xl font-bold dark:text-white sm:w-auto sm:text-3xl"> | ||
All Posts for {data.name} | ||
</h1> | ||
<a | ||
href={ | ||
process.env.NEXT_PUBLIC_VERCEL_ENV | ||
? `https://${url}` | ||
: `http://${data.subdomain}.localhost:3000` | ||
} | ||
target="_blank" | ||
rel="noreferrer" | ||
className="truncate rounded-md bg-stone-100 px-2 py-1 text-sm font-medium text-stone-600 transition-colors hover:bg-stone-200 dark:bg-stone-800 dark:text-stone-400 dark:hover:bg-stone-700" | ||
> | ||
{url} ↗ | ||
</a> | ||
</div> | ||
<CreatePostButton /> | ||
</div> | ||
<Posts siteId={params.siteId} /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
216 changes: 121 additions & 95 deletions
216
apps/application/components/app/navbar/store-switcher.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,110 +1,136 @@ | ||
"use client" | ||
"use client"; | ||
|
||
import * as React from "react" | ||
import { Check, ChevronsUpDown, PlusCircle, Store } from "lucide-react" | ||
import * as React from "react"; | ||
import { Check, ChevronsUpDown, PlusCircle, Store } from "lucide-react"; | ||
|
||
import { cn } from "@/lib/utils" | ||
import { Button } from "@/components/ui/button" | ||
import { cn } from "@/lib/utils"; | ||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Command, | ||
CommandEmpty, | ||
CommandGroup, | ||
CommandInput, | ||
CommandItem, | ||
CommandList, | ||
CommandSeparator, | ||
} from "@/components/ui/command" | ||
Command, | ||
CommandEmpty, | ||
CommandGroup, | ||
CommandInput, | ||
CommandItem, | ||
CommandList, | ||
CommandSeparator, | ||
} from "@/components/ui/command"; | ||
import { | ||
Popover, | ||
PopoverContent, | ||
PopoverTrigger, | ||
} from "@/components/ui/popover" | ||
Popover, | ||
PopoverContent, | ||
PopoverTrigger, | ||
} from "@/components/ui/popover"; | ||
// import { useStoreModal } from "@/hooks/use-store-modal" | ||
import { useParams, useRouter } from "next/navigation" | ||
import { useParams, useRouter } from "next/navigation"; | ||
|
||
type PopoverTriggerProps = React.ComponentPropsWithoutRef<typeof PopoverTrigger> | ||
type PopoverTriggerProps = React.ComponentPropsWithoutRef< | ||
typeof PopoverTrigger | ||
>; | ||
|
||
interface StoreSwitcherProps extends PopoverTriggerProps { | ||
items: Record<string, any>[]; | ||
items: Record<string, any>[]; | ||
} | ||
|
||
export default function StoreSwitcher({ className, items = [] }: StoreSwitcherProps) { | ||
// const storeModal = useStoreModal(); | ||
const params = useParams(); | ||
const router = useRouter(); | ||
export default function StoreSwitcher({ | ||
className, | ||
items = [], | ||
}: StoreSwitcherProps) { | ||
// const storeModal = useStoreModal(); | ||
const params = useParams(); | ||
const router = useRouter(); | ||
const [sites, setSites] = React.useState< | ||
{ | ||
name: string; | ||
id: string; | ||
}[] | ||
>([]); | ||
const handleFetchSites = () => { | ||
// fetch sites | ||
fetch("/api/sites") | ||
.then((res) => res.json()) | ||
.then((res) => { | ||
console.log(res, "sites"); | ||
setSites(res.result); | ||
}) | ||
.catch((err) => console.log(err)); | ||
}; | ||
React.useEffect(() => { | ||
handleFetchSites(); | ||
}, []); | ||
|
||
const formattedItems = items.map((item) => ({ | ||
label: item.name, | ||
value: item.id | ||
})); | ||
const formattedItems = sites.map((item) => ({ | ||
label: item.name, | ||
value: item.id, | ||
})); | ||
|
||
const currentStore = formattedItems.find((item) => item.value === params.storeId); | ||
const currentStore = formattedItems.find( | ||
(item) => item.value === params.siteId, | ||
); | ||
|
||
const [open, setOpen] = React.useState(false) | ||
const [open, setOpen] = React.useState(false); | ||
|
||
const onStoreSelect = (store: { value: string, label: string }) => { | ||
setOpen(false); | ||
router.push(`/${store.value}`); | ||
}; | ||
const onStoreSelect = (store: { value: string; label: string }) => { | ||
setOpen(false); | ||
router.push(`/${store.value}`); | ||
}; | ||
|
||
return ( | ||
<Popover open={open} onOpenChange={setOpen}> | ||
<PopoverTrigger asChild> | ||
<Button | ||
variant="outline" | ||
size="sm" | ||
role="combobox" | ||
aria-expanded={open} | ||
aria-label="Select a store" | ||
className={cn("w-[200px] justify-between", className)} | ||
> | ||
<Store className="mr-2 h-4 w-4" /> | ||
{currentStore?.label} | ||
<ChevronsUpDown className="ml-auto h-4 w-4 shrink-0 opacity-50" /> | ||
</Button> | ||
</PopoverTrigger> | ||
<PopoverContent className="w-[200px] p-0"> | ||
<Command> | ||
<CommandList> | ||
<CommandInput placeholder="Search store..." /> | ||
<CommandEmpty>No store found.</CommandEmpty> | ||
<CommandGroup heading="Stores"> | ||
{formattedItems.map((store) => ( | ||
<CommandItem | ||
key={store.value} | ||
onSelect={() => onStoreSelect(store)} | ||
className="text-sm" | ||
> | ||
<Store className="mr-2 h-4 w-4" /> | ||
{store.label} | ||
<Check | ||
className={cn( | ||
"ml-auto h-4 w-4", | ||
currentStore?.value === store.value | ||
? "opacity-100" | ||
: "opacity-0" | ||
)} | ||
/> | ||
</CommandItem> | ||
))} | ||
</CommandGroup> | ||
</CommandList> | ||
<CommandSeparator /> | ||
<CommandList> | ||
<CommandGroup> | ||
<CommandItem | ||
onSelect={() => { | ||
setOpen(false) | ||
// storeModal.onOpen() | ||
}} | ||
> | ||
<PlusCircle className="mr-2 h-5 w-5" /> | ||
Create Store | ||
</CommandItem> | ||
</CommandGroup> | ||
</CommandList> | ||
</Command> | ||
</PopoverContent> | ||
</Popover> | ||
); | ||
}; | ||
return ( | ||
<Popover open={open} onOpenChange={setOpen}> | ||
<PopoverTrigger asChild> | ||
<Button | ||
variant="outline" | ||
size="sm" | ||
role="combobox" | ||
aria-expanded={open} | ||
aria-label="Select a store" | ||
className={cn("w-[200px] justify-between", className)} | ||
> | ||
<Store className="mr-2 h-4 w-4" /> | ||
{currentStore?.label} | ||
<ChevronsUpDown className="ml-auto h-4 w-4 shrink-0 opacity-50" /> | ||
</Button> | ||
</PopoverTrigger> | ||
<PopoverContent className="w-[200px] p-0"> | ||
<Command> | ||
<CommandList> | ||
<CommandInput placeholder="Search store..." /> | ||
<CommandEmpty>No store found.</CommandEmpty> | ||
<CommandGroup heading="Stores"> | ||
{formattedItems.map((store) => ( | ||
<CommandItem | ||
key={store.value} | ||
onSelect={() => onStoreSelect(store)} | ||
className="text-sm" | ||
> | ||
<Store className="mr-2 h-4 w-4" /> | ||
{store.label} | ||
<Check | ||
className={cn( | ||
"ml-auto h-4 w-4", | ||
currentStore?.value === store.value | ||
? "opacity-100" | ||
: "opacity-0", | ||
)} | ||
/> | ||
</CommandItem> | ||
))} | ||
</CommandGroup> | ||
</CommandList> | ||
<CommandSeparator /> | ||
<CommandList> | ||
<CommandGroup> | ||
<CommandItem | ||
onSelect={() => { | ||
setOpen(false); | ||
// storeModal.onOpen() | ||
}} | ||
> | ||
<PlusCircle className="mr-2 h-5 w-5" /> | ||
Create Store | ||
</CommandItem> | ||
</CommandGroup> | ||
</CommandList> | ||
</Command> | ||
</PopoverContent> | ||
</Popover> | ||
); | ||
} |