feat: integrate landing page with real API and add CMS to backoffice
Landing page: - Events page now fetches from /v1/landing/cms/events (was hardcoded JSON) - Testimonials section and page fetch from /v1/landing/cms/testimonials - Removed dummy data, uses ISR with 60s revalidation - Replaced thumbnail images with text-based cards (API has no thumbnails) - Avatar initials for testimonials instead of placeholder images Backoffice CMS: - Added Events management page (/cms-events) with full CRUD - Added Testimonials management page (/cms-testimonials) with full CRUD - Both follow existing backoffice patterns (DataTable, modals, search, pagination) - Added CMS section to sidebar navigation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
414e4d19b8
commit
2cba806cd5
@@ -0,0 +1,166 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
import { Button } from '@imphnen-frontend-service/ui/atoms';
|
||||
import { Modal } from '@imphnen-frontend-service/ui/molecules';
|
||||
import { ControlledInputField } from '@imphnen-frontend-service/ui/organisms';
|
||||
|
||||
interface IModalUpdateEvent {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
handleUpdate?: () => Promise<boolean>;
|
||||
currentStep?: number;
|
||||
nextStep: () => void;
|
||||
prevStep: () => void;
|
||||
resetStep: () => void;
|
||||
initialValues?: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
detail_link?: string;
|
||||
location?: string;
|
||||
price?: number;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
is_online?: boolean;
|
||||
};
|
||||
onDataCapture?: (data: any) => void;
|
||||
}
|
||||
|
||||
const ModalUpdateEvent = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
resetStep,
|
||||
handleUpdate,
|
||||
initialValues,
|
||||
onDataCapture,
|
||||
}: IModalUpdateEvent) => {
|
||||
const form = useForm<any>({
|
||||
mode: 'all',
|
||||
defaultValues: initialValues,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
form.reset(initialValues);
|
||||
}
|
||||
}, [isOpen, initialValues]);
|
||||
|
||||
const onSubmit = form.handleSubmit(async (data) => {
|
||||
try {
|
||||
onDataCapture?.(data);
|
||||
if (handleUpdate) await handleUpdate();
|
||||
toast.success('Perubahan event berhasil dilakukan');
|
||||
onClose();
|
||||
resetStep();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error('Perubahan event gagal dilakukan');
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="min-w-[400px] bg-primary-50 rounded-lg p-[40px] flex flex-col gap-0 text-center"
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
disableEscapeKeyDown={true}
|
||||
>
|
||||
<Modal.Header>
|
||||
<h2 className="text-p1 font-semibold text-primary-500 mb-3">
|
||||
Update Event
|
||||
</h2>
|
||||
</Modal.Header>
|
||||
<Modal.Content className="flex flex-col gap-8">
|
||||
<form onSubmit={onSubmit} className="flex flex-col gap-8">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ControlledInputField
|
||||
control={form.control}
|
||||
label="Nama Event"
|
||||
name="name"
|
||||
type="text"
|
||||
placeholder="Masukkan Nama Event"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
/>
|
||||
<ControlledInputField
|
||||
control={form.control}
|
||||
label="Deskripsi"
|
||||
name="description"
|
||||
type="text"
|
||||
placeholder="Masukkan Deskripsi Event"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
/>
|
||||
<ControlledInputField
|
||||
control={form.control}
|
||||
label="Link Detail"
|
||||
name="detail_link"
|
||||
type="text"
|
||||
placeholder="Masukkan Link Detail"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
/>
|
||||
<ControlledInputField
|
||||
control={form.control}
|
||||
label="Lokasi"
|
||||
name="location"
|
||||
type="text"
|
||||
placeholder="Masukkan Lokasi"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
/>
|
||||
<ControlledInputField
|
||||
control={form.control}
|
||||
label="Harga"
|
||||
name="price"
|
||||
type="number"
|
||||
placeholder="Masukkan Harga"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
/>
|
||||
<ControlledInputField
|
||||
control={form.control}
|
||||
label="Tanggal Mulai"
|
||||
name="start_date"
|
||||
type="date"
|
||||
placeholder="Pilih Tanggal Mulai"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
/>
|
||||
<ControlledInputField
|
||||
control={form.control}
|
||||
label="Tanggal Selesai"
|
||||
name="end_date"
|
||||
type="date"
|
||||
placeholder="Pilih Tanggal Selesai"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="is_online_update"
|
||||
className="rounded"
|
||||
{...form.register('is_online')}
|
||||
/>
|
||||
<label htmlFor="is_online_update" className="text-p3 font-medium text-neutral-800">
|
||||
Event Online
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="primary"
|
||||
size="lg"
|
||||
className="w-full"
|
||||
type="submit"
|
||||
>
|
||||
Update Event
|
||||
</Button>
|
||||
</form>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalUpdateEvent;
|
||||
Reference in New Issue
Block a user