Updated list component
This commit is contained in:
@@ -12,7 +12,7 @@ import {
|
|||||||
useReactTable,
|
useReactTable,
|
||||||
VisibilityState
|
VisibilityState
|
||||||
} from "@tanstack/react-table"
|
} from "@tanstack/react-table"
|
||||||
import { ArrowUpDown, Check, Copy, ExternalLink, MoreHorizontal, Trash2, X } from "lucide-react"
|
import { ArrowUpDown, Check, Copy, MoreHorizontal, Trash2, X } from "lucide-react"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
@@ -27,19 +27,13 @@ import {
|
|||||||
} from "@/components/ui/dropdown-menu"
|
} from "@/components/ui/dropdown-menu"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
|
import { deleteUrl } from "@/lib/actions/url"
|
||||||
import { urls } from "@/lib/drizzle/schema"
|
import { urls } from "@/lib/drizzle/schema"
|
||||||
|
import { useRouter } from "next/navigation"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
|
|
||||||
type UrlRecord = typeof urls.$inferSelect
|
type UrlRecord = typeof urls.$inferSelect
|
||||||
|
|
||||||
function handleCopy(string: string) {
|
|
||||||
navigator.clipboard.writeText(string).then(() => {
|
|
||||||
toast.success("URL copied to clipboard")
|
|
||||||
}).catch(() => {
|
|
||||||
toast.error("Failed to copy URL")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const columns: ColumnDef<UrlRecord>[] = [
|
export const columns: ColumnDef<UrlRecord>[] = [
|
||||||
{
|
{
|
||||||
accessorKey: "slug",
|
accessorKey: "slug",
|
||||||
@@ -202,8 +196,39 @@ export const columns: ColumnDef<UrlRecord>[] = [
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
{
|
]
|
||||||
|
|
||||||
|
interface UrlsDataTableProps {
|
||||||
|
data: UrlRecord[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UrlsDataTable({ data }: UrlsDataTableProps) {
|
||||||
|
const [sorting, setSorting] = React.useState<SortingState>([])
|
||||||
|
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
|
||||||
|
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
function handleCopy(string: string) {
|
||||||
|
navigator.clipboard.writeText(string).then(() => {
|
||||||
|
toast.success("URL copied to clipboard")
|
||||||
|
}).catch(() => {
|
||||||
|
toast.error("Failed to copy URL")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDelete(id: string) {
|
||||||
|
const res = await deleteUrl(id)
|
||||||
|
|
||||||
|
if (res.error) {
|
||||||
|
toast.error("Failed to delete URL")
|
||||||
|
} else {
|
||||||
|
toast.success("URL deleted successfully")
|
||||||
|
router.refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionRow: ColumnDef<UrlRecord> = {
|
||||||
id: "actions",
|
id: "actions",
|
||||||
enableHiding: false,
|
enableHiding: false,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
@@ -228,7 +253,12 @@ export const columns: ColumnDef<UrlRecord>[] = [
|
|||||||
Copy URL
|
Copy URL
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem className="text-red-600">
|
<DropdownMenuItem
|
||||||
|
className="text-red-600"
|
||||||
|
onClick={() => {
|
||||||
|
handleDelete(urlRecord.id)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Trash2 className="mr-2 h-4 w-4" />
|
<Trash2 className="mr-2 h-4 w-4" />
|
||||||
Delete
|
Delete
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
@@ -237,20 +267,12 @@ export const columns: ColumnDef<UrlRecord>[] = [
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
|
||||||
interface UrlsDataTableProps {
|
const tableColumns = React.useMemo(() => [...columns, actionRow], [])
|
||||||
data: UrlRecord[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export function UrlsDataTable({ data }: UrlsDataTableProps) {
|
|
||||||
const [sorting, setSorting] = React.useState<SortingState>([])
|
|
||||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
|
|
||||||
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
|
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data,
|
||||||
columns,
|
columns: tableColumns,
|
||||||
onSortingChange: setSorting,
|
onSortingChange: setSorting,
|
||||||
onColumnFiltersChange: setColumnFilters,
|
onColumnFiltersChange: setColumnFilters,
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
@@ -341,7 +363,7 @@ export function UrlsDataTable({ data }: UrlsDataTableProps) {
|
|||||||
(
|
(
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
colSpan={columns.length}
|
colSpan={tableColumns.length}
|
||||||
className="h-24 text-center"
|
className="h-24 text-center"
|
||||||
>
|
>
|
||||||
No results.
|
No results.
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
"use server"
|
"use server"
|
||||||
|
|
||||||
|
import { z } from "zod"
|
||||||
import { getSession } from "../auth/session"
|
import { getSession } from "../auth/session"
|
||||||
import { insertUrl } from "../db/urls"
|
import { insertUrl } from "../db/urls"
|
||||||
import { urlFormSchema } from "../schema/url"
|
import { urlFormSchema } from "../schema/url"
|
||||||
|
import { deleteUrl as deleteUrlDb } from "../db/urls"
|
||||||
|
|
||||||
type Response = {
|
type Response = {
|
||||||
error: boolean
|
error: boolean
|
||||||
@@ -34,4 +36,31 @@ export async function addUrl(unsafeData: unknown): Promise<Response> {
|
|||||||
error: false,
|
error: false,
|
||||||
message: "Short link created successfully!"
|
message: "Short link created successfully!"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteUrl(unsafe: unknown): Promise<Response> {
|
||||||
|
const { session } = await getSession()
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return {
|
||||||
|
error: true,
|
||||||
|
message: "You must be logged in to create a short link."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { error, data: id } = z.string().safeParse(unsafe)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return {
|
||||||
|
error: true,
|
||||||
|
message: "Error parsing form data."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await deleteUrlDb(id)
|
||||||
|
|
||||||
|
return {
|
||||||
|
error: false,
|
||||||
|
message: "Short link deleted successfully!"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user