Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
93 lines
2.9 KiB
TypeScript
93 lines
2.9 KiB
TypeScript
'use client'
|
|
|
|
import { zodResolver } from '@hookform/resolvers/zod'
|
|
import { FormProvider, useForm } from 'react-hook-form'
|
|
|
|
import type { FaqItem } from '@/components/events/create/types'
|
|
import Button from '@/components/formElements/Button'
|
|
import TrashIcon from '@/components/icons/TrashIcon'
|
|
import { EventWizardFaqFormValidation, type EventWizardFaqFormValues } from '@/validation/eventWizard'
|
|
import { createClientId } from '@/lib/createClientId'
|
|
import { showFormValidationToast } from '@/lib/formValidationToast'
|
|
import { texts } from '@/texts'
|
|
import ConsumerButton from '@/components/consumer/ConsumerButton'
|
|
import ConsumerInput from '@/components/consumer/ConsumerInput'
|
|
|
|
interface FaqEditorProps {
|
|
items: FaqItem[]
|
|
onChange: (items: FaqItem[]) => void
|
|
}
|
|
|
|
/** Adds and removes optional common questions without coupling to wizard state. */
|
|
export default function FaqEditor({ items, onChange }: FaqEditorProps) {
|
|
const form = useForm<EventWizardFaqFormValues>({
|
|
resolver: zodResolver(EventWizardFaqFormValidation),
|
|
defaultValues: { answer: '', question: '' },
|
|
})
|
|
|
|
const addFaq = () => {
|
|
void form.handleSubmit((values) => {
|
|
onChange([
|
|
...items,
|
|
{
|
|
answer: values.answer,
|
|
id: createClientId(),
|
|
question: values.question,
|
|
},
|
|
])
|
|
form.reset({ answer: '', question: '' })
|
|
}, showFormValidationToast)()
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-col gap-2">
|
|
{items.map((item) => (
|
|
<article
|
|
key={item.id}
|
|
className="rounded-consumer-control bg-secondary-50 p-3"
|
|
>
|
|
<div className="w-full flex items-start justify-between">
|
|
<div className="min-w-0">
|
|
<p className="text-sm font-medium text-consumer-text">{item.question}</p>
|
|
<p className="mt-1 text-xs leading-5 text-secondary-20">{item.answer}</p>
|
|
</div>
|
|
<Button
|
|
iconOnly
|
|
aria-label={texts.common.delete}
|
|
className="size-8 shrink-0 rounded-lg text-tertiary-900 hover:bg-white/70"
|
|
variant="light"
|
|
onClick={() => {
|
|
onChange(items.filter((faq) => faq.id !== item.id))
|
|
}}
|
|
>
|
|
<TrashIcon className="size-4 text-fourth" />
|
|
</Button>
|
|
</div>
|
|
</article>
|
|
))}
|
|
|
|
<FormProvider {...form}>
|
|
<div className="grid gap-2">
|
|
<ConsumerInput
|
|
generalType="input"
|
|
label={texts.events.questionLabel}
|
|
name="question"
|
|
/>
|
|
<ConsumerInput
|
|
generalType="input"
|
|
label={texts.common.reply}
|
|
name="answer"
|
|
/>
|
|
<ConsumerButton
|
|
fill="gray"
|
|
size="xs"
|
|
onClick={addFaq}
|
|
>
|
|
{texts.events.addQuestion}
|
|
</ConsumerButton>
|
|
</div>
|
|
</FormProvider>
|
|
</div>
|
|
)
|
|
}
|