-
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.
feat(dash/admin): ✨ FAQ List and Editor
- Loading branch information
1 parent
3752421
commit 66e2db9
Showing
16 changed files
with
761 additions
and
248 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 |
---|---|---|
@@ -1,2 +1 @@ | ||
export const LIB_VERSION = '1.1.0'; | ||
export const LIB_LICENSE = undefined; | ||
export const LIB_VERSION = "1.1.0";export const LIB_LICENSE = undefined; |
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
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
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,44 @@ | ||
'use server'; | ||
|
||
import prisma from '@/util/db'; | ||
import { revalidatePath } from 'next/cache'; | ||
|
||
export const addFaqQuestion = async (data: { question: string; answer: string }) => { | ||
const { question, answer } = data; | ||
|
||
const faq = await prisma.fAQQuestion.create({ | ||
data: { | ||
question, | ||
answer, | ||
}, | ||
}); | ||
|
||
revalidatePath('/am/faq'); | ||
return faq; | ||
}; | ||
|
||
export const editFaqQuestion = async (data: { question: string; answer: string; id: string }) => { | ||
const faq = await prisma.fAQQuestion.update({ | ||
where: { | ||
id: data.id, | ||
}, | ||
data: { | ||
question: data.question, | ||
answer: data.answer, | ||
}, | ||
}); | ||
|
||
revalidatePath('/am/faq'); | ||
return faq; | ||
}; | ||
|
||
export const deleteFaqQuestion = async (id: any) => { | ||
const faq = await prisma.fAQQuestion.delete({ | ||
where: { | ||
id, | ||
}, | ||
}); | ||
|
||
revalidatePath('/am/faq'); | ||
return faq; | ||
}; |
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
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,116 @@ | ||
'use client'; | ||
|
||
import { addFaqQuestion, deleteFaqQuestion, editFaqQuestion } from '@/app/actions'; | ||
import { ActionIcon, Button, Group, InputWrapper, TextInput } from '@mantine/core'; | ||
import { IconDeviceFloppy, IconEdit, IconPlus, IconTrash } from '@tabler/icons-react'; | ||
|
||
import RichTextEditor from '@/components/input/RTE'; | ||
import { useFormActions } from '@/hooks/useFormAction'; | ||
import { useForm } from '@mantine/form'; | ||
import { modals } from '@mantine/modals'; | ||
import { FAQQuestion } from '@repo/db'; | ||
|
||
export function AddFaqQuestionButton() { | ||
return ( | ||
<Button | ||
color="green" | ||
leftSection={<IconPlus size={14} />} | ||
onClick={() => | ||
modals.open({ | ||
id: 'add-faq-question', | ||
title: 'Add new FAQ Question', | ||
centered: true, | ||
size: 'lg', | ||
children: <EditFaqQuestionModal isAdd id="" question="" answer="" links={[]} />, | ||
}) | ||
} | ||
> | ||
Add New | ||
</Button> | ||
); | ||
} | ||
|
||
export function EditFaqQuestionButton(props: FAQQuestion) { | ||
return ( | ||
<ActionIcon | ||
size="sm" | ||
variant="subtle" | ||
color="yellow" | ||
aria-label="Edit Question" | ||
onClick={() => | ||
modals.open({ | ||
id: 'edit-faq-question', | ||
title: 'Edit FAQ Question', | ||
centered: true, | ||
size: 'lg', | ||
children: <EditFaqQuestionModal {...props} />, | ||
}) | ||
} | ||
> | ||
<IconEdit size={16} /> | ||
</ActionIcon> | ||
); | ||
} | ||
|
||
function EditFaqQuestionModal( | ||
props: { | ||
isAdd?: boolean; | ||
} & FAQQuestion, | ||
) { | ||
const form = useForm({ | ||
initialValues: { id: props.id, question: props.question, answer: props.answer, links: props.links }, | ||
}); | ||
const [[addFaqQuestionAction,editFaqQuestionAction, deleteFaqQuestionAction], isPending] = useFormActions([ | ||
addFaqQuestion, | ||
editFaqQuestion, | ||
deleteFaqQuestion, | ||
]); | ||
|
||
const handleSubmit = (values: FAQQuestion) => { | ||
if (props.isAdd) { | ||
addFaqQuestionAction(values); | ||
} else { | ||
editFaqQuestionAction(values); | ||
} | ||
modals.closeAll(); | ||
}; | ||
|
||
return ( | ||
<form onSubmit={form.onSubmit(handleSubmit)}> | ||
<TextInput | ||
mt="md" | ||
placeholder="How can i ... ?" | ||
label="Question" | ||
description="Question to display on top" | ||
required | ||
{...form.getInputProps('question')} | ||
/> | ||
<InputWrapper label="Answer" mt="md" required description="Answer to the question"> | ||
<RichTextEditor style={{ marginTop: '5px' }} {...form.getInputProps('answer')} /> | ||
</InputWrapper> | ||
{!props.isAdd ? ( | ||
<Group mt="md"> | ||
<Button type="submit" leftSection={<IconDeviceFloppy size={14} />} loading={isPending}> | ||
Save Changes | ||
</Button> | ||
<Button | ||
variant="outline" | ||
onClick={() => { | ||
deleteFaqQuestionAction(props.id); | ||
modals.closeAll(); | ||
}} | ||
leftSection={<IconTrash size={14} />} | ||
color="red" | ||
loading={isPending} | ||
> | ||
Delete Question | ||
</Button> | ||
</Group> | ||
) : ( | ||
<Button type="submit" mt="md" leftSection={<IconPlus size={14} />} loading={isPending}> | ||
Add Question | ||
</Button> | ||
)} | ||
</form> | ||
); | ||
} |
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
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
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,18 @@ | ||
"use client" | ||
|
||
import { Button, ButtonProps, PolymorphicComponentProps } from '@mantine/core'; | ||
import { useEffect, useState } from 'react'; | ||
|
||
import { useFormStatus } from 'react-dom'; | ||
|
||
export function FormButton(props: PolymorphicComponentProps<"button", ButtonProps>) { | ||
const {pending} = useFormStatus(); | ||
const [isLoading, setIsLoading] = useState(false); | ||
|
||
useEffect(() => { | ||
console.log(new Date().toISOString(), "pending: "+pending) | ||
setIsLoading(pending); | ||
}, [pending]); | ||
|
||
return <Button loading={isLoading} {...props} />; | ||
} |
Oops, something went wrong.