Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/app/dashboard/(active)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Globe } from "lucide-react"
import Image from "next/image"
import Link from "next/link"
import azureSvg from "@/assets/svg/azure.svg"
Expand Down Expand Up @@ -38,6 +39,18 @@ export default async function AdminHome() {
</CardHeader>
</Card>
</Link>

<Link href="/dashboard/web">
<Card className="w-90 hover:bg-accent transition-colors">
<CardHeader>
<CardTitle className="flex gap-2">
<Globe className="size-5" />
Web
</CardTitle>
<CardDescription>Manage website related things</CardDescription>
</CardHeader>
</Card>
</Link>
</div>
</div>
)
Expand Down
2 changes: 1 addition & 1 deletion src/app/dashboard/(active)/telegram/groups/group-row.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client"
import { Copy, Pen } from "lucide-react"
import { Copy } from "lucide-react"
import { useRouter } from "next/navigation"
import { toast } from "sonner"
import { Badge } from "@/components/ui/badge"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { useSession } from "@/lib/auth"
import { delUserRole } from "@/server/actions/users"
import type { ApiOutput, TgUser, TgUserRole } from "@/server/trpc/types"
import type { TgUser, TgUserRole } from "@/server/trpc/types"

const ARRAY_USER_ROLES = [
USER_ROLE.ADMIN,
Expand Down
105 changes: 105 additions & 0 deletions src/app/dashboard/(active)/web/faqs/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"use client" //Serve?

import { ArrowLeft, LucidePencil, PlusIcon, Trash } from "lucide-react"
import Link from "next/link"
import { toast } from "sonner"
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
import { Button } from "@/components/ui/button"

interface FaqsData {
question: string
answer: string
}

const data: FaqsData[] = [
{ question: "What is the price of a house?", answer: "1 million dollars" },
{ question: "What is the price of a car?", answer: "100 thousand dollars" },
{ question: "What is the price of a bike?", answer: "10 thousand dollars" },
{ question: "What is the price of a boat?", answer: "100 million dollars" },
{ question: "What is the price of a plane?", answer: "1 billion dollars" },
]

export default function WebFaqsIndex() {
const handleAdd = (e: React.MouseEvent) => {
e.stopPropagation()
toast.info("Adding FAQ")
}

const handleEdit = (e: React.MouseEvent, question: string) => {
e.stopPropagation()
toast.warning(`Editing FAQ: "${question}"`)
}

const handleDelete = (e: React.MouseEvent, question: string) => {
e.stopPropagation()
toast.error(`Deleting FAQ: "${question}"`)
}

return (
<div className="container max-w-4xl py-10">
<div className="space-y-6">
<div>
<Link
href="/dashboard/web"
className="inline-flex gap-1 items-center text-sm text-muted-foreground hover:text-foreground mb-4 transition-colors group"
>
<ArrowLeft size={16} className="transition-transform group-hover:-translate-x-0.5" /> Back
</Link>
<div className="flex justify-between items-center w-full">
<div>
<h1 className="text-3xl font-bold tracking-tight bg-gradient-to-r from-foreground via-foreground/90 to-foreground/75 bg-clip-text text-transparent">
Frequently Asked Questions
</h1>
<p className="text-muted-foreground mt-1.5 text-sm">
Manage and view FAQs displayed on the web platform.
</p>
</div>
<Button onClick={handleAdd}>
<PlusIcon className="size-4" />
Add FAQ
</Button>
</div>
</div>

<Accordion className="gap-3.5">
{data.map((item, index) => (
<AccordionItem
key={index}
value={index.toString()}
className="group rounded-xl border border-border/80 bg-card/60 backdrop-blur-sm px-5 py-0.5 transition-all duration-300 hover:border-primary/20 hover:bg-card/90 hover:shadow-md hover:shadow-primary/2 data-[open]:border-primary/30 data-[open]:bg-card data-[open]:shadow-md data-[open]:shadow-primary/5"
>
<AccordionTrigger
className="font-medium text-foreground/90 transition-colors py-4 hover:no-underline group-hover:text-primary/90"
actions={
<div className="flex items-center gap-1.5">
<Button
type="button"
onClick={(e) => handleEdit(e, item.question)}
aria-label="Edit FAQ"
className="flex size-8 items-center justify-center rounded-lg border border-border bg-card text-muted-foreground hover:text-foreground hover:border-primary/30 hover:bg-accent transition-all duration-200 cursor-pointer shadow-sm"
>
<LucidePencil className="size-3.5" />
</Button>
<Button
type="button"
onClick={(e) => handleDelete(e, item.question)}
aria-label="Delete FAQ"
className="flex size-8 items-center justify-center rounded-lg border border-border bg-card text-muted-foreground hover:text-destructive hover:border-destructive/30 hover:bg-destructive/10 transition-all duration-200 cursor-pointer shadow-sm"
>
<Trash className="size-3.5" />
</Button>
</div>
}
>
{item.question}
</AccordionTrigger>
<AccordionContent className="text-muted-foreground pb-4 leading-relaxed">
<p>{item.answer}</p>
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
</div>
)
}
27 changes: 27 additions & 0 deletions src/app/dashboard/(active)/web/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { CircleQuestionMark, Globe } from "lucide-react"
import Link from "next/link"
import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"

export default function WebIndex() {
return (
<div className="container py-8 px-2 flex flex-col gap-4">
<h2 className="text-accent-foreground text-3xl font-bold flex gap-2 items-center">
<Globe className="size-7" />
Web
</h2>
<div className="gap-4 flex justify-start flex-wrap items-center">
<Link href="/dashboard/web/faqs">
<Card className="w-90 hover:bg-accent transition-colors">
<CardHeader>
<CardTitle className="flex gap-2 items-center">
<CircleQuestionMark size={20} />
FAQs
</CardTitle>
<CardDescription>Manage FAQs</CardDescription>
</CardHeader>
</Card>
</Link>
</div>
</div>
)
}
3 changes: 3 additions & 0 deletions src/components/admin-header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export function AdminHeader() {
<Link href="/dashboard/telegram" className="hover:underline">
Telegram
</Link>
<Link href="/dashboard/web" className="hover:underline">
Web
</Link>
</nav>
<nav className="flex justify-end items-center h-full">
<RightNav />
Expand Down
85 changes: 85 additions & 0 deletions src/components/ui/accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as React from "react"
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"

import { cn } from "@/lib/utils/shadcn"
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"

function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
return (
<AccordionPrimitive.Root
data-slot="accordion"
className={cn("flex w-full flex-col", className)}
{...props}
/>
)
}

function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
return (
<AccordionPrimitive.Item
data-slot="accordion-item"
className={cn("not-last:border-b", className)}
{...props}
/>
)
}

interface AccordionTriggerProps extends AccordionPrimitive.Trigger.Props {
actions?: React.ReactNode
}

function AccordionTrigger({
className,
children,
actions,
...props
}: AccordionTriggerProps) {
return (
<AccordionPrimitive.Header className="flex w-full items-center gap-2">
<AccordionPrimitive.Trigger
data-slot="accordion-trigger"
className={cn(
"group/accordion-trigger relative flex flex-1 items-center justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50",
className
)}
{...props}
>
{children}
<ChevronDownIcon data-slot="accordion-trigger-icon" className="pointer-events-none shrink-0 ml-auto size-4 text-muted-foreground group-aria-expanded/accordion-trigger:hidden" />
<ChevronUpIcon data-slot="accordion-trigger-icon" className="pointer-events-none hidden shrink-0 ml-auto size-4 text-muted-foreground group-aria-expanded/accordion-trigger:inline" />
</AccordionPrimitive.Trigger>
{actions && (
<div className="flex items-center gap-1.5 shrink-0 z-10">
{actions}
</div>
)}
</AccordionPrimitive.Header>
)
}

function AccordionContent({
className,
children,
...props
}: AccordionPrimitive.Panel.Props) {
return (
<AccordionPrimitive.Panel
data-slot="accordion-content"
className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
{...props}
>
<div
className={cn(
"h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
className
)}
>
{children}
</div>
</AccordionPrimitive.Panel>
)
}

export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
export type { AccordionTriggerProps }

Loading