184 lines
5.1 KiB
TypeScript
184 lines
5.1 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useState } from 'react'
|
|
import { Button } from '@/components/ui/button'
|
|
import { PlusCircle } from 'lucide-react'
|
|
import { MarkCardI, MarkLinkI } from '@/lib/markcard/card'
|
|
import { Label } from "@/components/ui/label"
|
|
import { Input } from "@/components/ui/input"
|
|
import EditCardModal from './EditMarkCardModal'
|
|
import MarkCardGrid from './MarkCardGrid'
|
|
import { notFound } from 'next/navigation'
|
|
import path from 'path'
|
|
|
|
|
|
interface CardContainerProps {
|
|
userId?: string
|
|
canEdit?: boolean
|
|
fileUrl?: string[]
|
|
}
|
|
|
|
export default function MarkCards({ canEdit, userId, fileUrl }: CardContainerProps) {
|
|
const baseUrl = '/api/card'
|
|
const userUrl = `${baseUrl}${userId ? `/${userId}` : ''}`
|
|
const url = path.join(userUrl, ...(fileUrl || []))
|
|
const [validToken, setValidToken] = useState<boolean>(canEdit ? true : false)
|
|
const [token, setToken] = useState<string>('')
|
|
const [isEditModalOpen, setIsEditModalOpen] = useState<boolean>(false)
|
|
const [cards, setCards] = useState<MarkCardI[] | undefined>([])
|
|
const [card, setCard] = useState<{
|
|
id: string
|
|
card: MarkCardI
|
|
}>()
|
|
const fetchData = async () => {
|
|
console.log('fetching')
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET'
|
|
})
|
|
|
|
if (!response.ok) {
|
|
setCards(undefined)
|
|
return notFound()
|
|
}
|
|
|
|
const retcards = await (response.json()) as MarkCardI[]
|
|
|
|
setCards(retcards)
|
|
} catch (error) {
|
|
console.error('Error fetching data:', error)
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
fetchData()
|
|
}, [])
|
|
|
|
const onEditMarkCard = async (id: string, updatedData: Partial<MarkLinkI>) => {
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'PATCH',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(updatedData),
|
|
})
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to update card')
|
|
}
|
|
|
|
setCards((prevCards) =>
|
|
prevCards?.map((card) => (card.id === id ? { ...card, ...updatedData } : card))
|
|
)
|
|
} catch (error) {
|
|
console.error('Error updating card:', error)
|
|
}
|
|
}
|
|
|
|
const onAddMarkCard = async () => {
|
|
const newCard: MarkCardI = {
|
|
id: '',
|
|
title: 'New Bookmark',
|
|
shortDescription: 'Add a description',
|
|
links: [{ title: 'Add a link', url: 'https://example.com' }],
|
|
}
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(newCard),
|
|
})
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to add card')
|
|
}
|
|
|
|
const realNewCard = await response.json()
|
|
setCards((prevCards) => [...prevCards ?? [], realNewCard])
|
|
} catch (error) {
|
|
console.error('Error adding card:', error)
|
|
}
|
|
}
|
|
|
|
const onVailidate = async (token: string, override?: boolean) => {
|
|
if (!override && validToken === true) {
|
|
return
|
|
}
|
|
try {
|
|
const response = await fetch('/api/card/validate', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ userId, token }),
|
|
})
|
|
|
|
if (!response.ok) {
|
|
setValidToken(false)
|
|
} else {
|
|
setValidToken((await response.json()).validate ?? false)
|
|
}
|
|
} catch {
|
|
setValidToken(false)
|
|
}
|
|
}
|
|
|
|
const onEdit = (id: string, origin: MarkCardI) => {
|
|
setCard({id, card: {...origin}})
|
|
console.log(id, origin)
|
|
setIsEditModalOpen(true)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-8 container">
|
|
<div className="flex justify-between space-x-4">
|
|
<div className='flex space-x-4'>
|
|
<Label
|
|
htmlFor='token-input'
|
|
className='flex items-center whitespace-nowrap text-xl font-bold'>
|
|
Card For
|
|
</Label>
|
|
<Input
|
|
className='flex border-none shadow-none max-w-[50vw]'
|
|
placeholder='TOKEN'
|
|
id='token-input'
|
|
value={token}
|
|
onChange={(e) => setToken(e.target.value)}
|
|
onBlur={(_) => onVailidate(token)}
|
|
/>
|
|
</div>
|
|
<div className='flex'>
|
|
{validToken && (
|
|
<div className="flex justify-end space-x-4">
|
|
<Button onClick={() => { setValidToken(false); setToken(''); fetchData()} }>Disable Edit</Button>
|
|
<Button onClick={onAddMarkCard}>
|
|
<PlusCircle className="mr-2 h-4 w-4" />
|
|
Add New Bookmark
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
{
|
|
cards === undefined ? notFound() :
|
|
<MarkCardGrid cards={cards} onEdit={onEdit} baseUrl={'/markcard'} canEdit={validToken} />
|
|
}
|
|
{validToken && card && (
|
|
<EditCardModal
|
|
isOpen={isEditModalOpen}
|
|
onClose={() => { setIsEditModalOpen(false); setCard(undefined) }}
|
|
cardData={card.card}
|
|
onSave={(updatedData) => {
|
|
onEditMarkCard(card.id, updatedData)
|
|
setCard(undefined)
|
|
setIsEditModalOpen(false)
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|