// React Imports import { useState, useEffect } from 'react' // MUI Imports import Button from '@mui/material/Button' import Drawer from '@mui/material/Drawer' import IconButton from '@mui/material/IconButton' import MenuItem from '@mui/material/MenuItem' import Typography from '@mui/material/Typography' import Divider from '@mui/material/Divider' import Grid from '@mui/material/Grid2' import Box from '@mui/material/Box' import Switch from '@mui/material/Switch' import FormControlLabel from '@mui/material/FormControlLabel' import Chip from '@mui/material/Chip' import InputAdornment from '@mui/material/InputAdornment' // Third-party Imports import { useForm, Controller, useFieldArray } from 'react-hook-form' // Component Imports import CustomTextField from '@core/components/mui/TextField' // Types import { Campaign } from '@/types/services/campaign' import { useCampaignsMutation } from '@/services/mutations/campaign' // Updated Type Definitions export type CampaignType = 'REWARD' | 'POINTS' | 'TOKENS' | 'MIXED' export type RuleType = 'TIER' | 'SPEND' | 'PRODUCT' | 'CATEGORY' | 'DAY' | 'LOCATION' export type RewardType = 'POINTS' | 'TOKENS' | 'REWARD' export interface CampaignRequest { name: string description?: string type: CampaignType start_date: string // ISO string end_date: string // ISO string is_active: boolean show_on_app: boolean position: number metadata?: Record rules: CampaignRuleRequest[] } export interface CampaignRuleRequest { rule_type: RuleType condition_value?: string reward_type: RewardType reward_value?: number reward_subtype?: string } type Props = { open: boolean handleClose: () => void data?: Campaign // Data campaign untuk edit (jika ada) } type FormValidateType = { name: string description: string type: CampaignType start_date: string end_date: string is_active: boolean show_on_app: boolean position: number // Rules array rules: { rule_type: RuleType condition_value: string reward_type: RewardType reward_value: number reward_subtype: string }[] } // Initial form data const initialData: FormValidateType = { name: '', description: '', type: 'POINTS', start_date: '', end_date: '', is_active: true, show_on_app: true, position: 1, // Initial rule rules: [ { rule_type: 'SPEND', condition_value: '', reward_type: 'POINTS', reward_value: 0, reward_subtype: '' } ] } const AddEditCampaignDrawer = (props: Props) => { // Props const { open, handleClose, data } = props // States const [showMore, setShowMore] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false) const { createCampaign, updateCampaign } = useCampaignsMutation() // Determine if this is edit mode const isEditMode = Boolean(data?.id) // Hooks const { control, reset: resetForm, handleSubmit, watch, setValue, formState: { errors } } = useForm({ defaultValues: initialData }) // Field array for rules const { fields, append, remove } = useFieldArray({ control, name: 'rules' }) const watchedStartDate = watch('start_date') const watchedEndDate = watch('end_date') // Effect to populate form when editing useEffect(() => { if (isEditMode && data) { const formData: FormValidateType = { name: data.name || '', description: data.description || '', type: data.type || 'POINTS', start_date: data.start_date ? new Date(data.start_date).toISOString().split('T')[0] : '', end_date: data.end_date ? new Date(data.end_date).toISOString().split('T')[0] : '', is_active: data.is_active ?? true, show_on_app: data.show_on_app ?? true, position: data.position || 1, // Map existing rules rules: data.rules?.map(rule => ({ rule_type: rule.rule_type, condition_value: rule.condition_value || '', reward_type: rule.reward_type, reward_value: rule.reward_value || 0, reward_subtype: rule.reward_subtype || '' })) || [ { rule_type: 'SPEND', condition_value: '', reward_type: 'POINTS', reward_value: 0, reward_subtype: '' } ] } resetForm(formData) setShowMore(true) // Always show more for edit mode } else { // Reset to initial data for add mode resetForm(initialData) setShowMore(false) } }, [data, isEditMode, resetForm]) const handleFormSubmit = async (formData: FormValidateType) => { try { setIsSubmitting(true) // Create rules array const rulesRequest: CampaignRuleRequest[] = formData.rules.map(rule => ({ rule_type: rule.rule_type, condition_value: rule.condition_value || undefined, reward_type: rule.reward_type, reward_value: rule.reward_value || undefined, reward_subtype: rule.reward_subtype || undefined })) // Create metadata from rules if needed const metadata: Record = {} const spendRule = formData.rules.find(rule => rule.rule_type === 'SPEND') if (spendRule?.condition_value) { metadata.minPurchase = parseInt(spendRule.condition_value) } // Create CampaignRequest object const campaignRequest: CampaignRequest = { name: formData.name, description: formData.description || undefined, type: formData.type, start_date: new Date(formData.start_date).toISOString(), end_date: new Date(formData.end_date).toISOString(), is_active: formData.is_active, show_on_app: formData.show_on_app, position: formData.position, metadata: Object.keys(metadata).length > 0 ? metadata : undefined, rules: rulesRequest } if (isEditMode && data?.id) { // Update existing campaign updateCampaign.mutate( { id: data.id, payload: campaignRequest }, { onSuccess: () => { handleReset() handleClose() } } ) } else { // Create new campaign createCampaign.mutate(campaignRequest, { onSuccess: () => { handleReset() handleClose() } }) } } catch (error) { console.error('Error submitting campaign:', error) // Handle error (show toast, etc.) } finally { setIsSubmitting(false) } } const handleReset = () => { handleClose() resetForm(initialData) setShowMore(false) } const formatCurrency = (value: number) => { return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(value) } const getRewardTypeLabel = (type: RewardType) => { switch (type) { case 'POINTS': return 'Poin' case 'TOKENS': return 'Token' case 'REWARD': return 'Reward' default: return type } } const getRewardValuePlaceholder = (type: RewardType) => { switch (type) { case 'POINTS': return 'Jumlah poin yang diberikan' case 'TOKENS': return 'Jumlah token yang diberikan' case 'REWARD': return 'Nilai reward' default: return 'Nilai reward' } } const getConditionValuePlaceholder = (ruleType: RuleType) => { switch (ruleType) { case 'SPEND': return 'Minimum pembelian (Rupiah)' case 'TIER': return 'Tier pelanggan (misal: GOLD, SILVER)' case 'PRODUCT': return 'ID atau nama produk' case 'CATEGORY': return 'Kategori produk' case 'DAY': return 'Hari dalam seminggu (misal: MONDAY)' case 'LOCATION': return 'Lokasi atau kota' default: return 'Nilai kondisi' } } const getConditionValueInputProps = (ruleType: RuleType) => { if (ruleType === 'SPEND') { return { startAdornment: Rp, type: 'number' as const } } return { type: 'text' as const } } return ( {/* Sticky Header */}
{isEditMode ? 'Edit Kampanye' : 'Tambah Kampanye Baru'}
{/* Scrollable Content */}
{/* Nama Kampanye */}
Nama Kampanye * ( )} />
{/* Jenis Kampanye */}
Jenis Kampanye * (
Points
Tokens
Reward
Mixed
)} />
{/* Rules Section */}
Aturan Kampanye {fields.map((field, index) => ( Aturan {index + 1} {fields.length > 1 && ( remove(index)}> )}
{/* Rule Type */}
Tipe Aturan * ( Minimum Pembelian Tier Pelanggan Produk Tertentu Kategori Produk Hari Tertentu Lokasi Tertentu )} />
{/* Condition Value */}
Nilai Kondisi * { const ruleType = watch(`rules.${index}.rule_type`) return ( ) }} />
{/* Reward Type */}
Jenis Reward * (
Points
Tokens
Reward
)} />
{/* Reward Value */}
Nilai Reward * { const rewardType = watch(`rules.${index}.reward_type`) return ( Poin ) : rewardType === 'TOKENS' ? ( Token ) : undefined }} onChange={e => field.onChange(Number(e.target.value))} /> ) }} />
{/* Reward Subtype (jika reward type adalah REWARD) */} {watch(`rules.${index}.reward_type`) === 'REWARD' && (
Sub-tipe Reward ( Diskon Persentase Diskon Nominal Cashback Gratis Ongkir )} />
)}
))}
{/* Tanggal Mulai */}
Tanggal Mulai * ( )} />
{/* Tanggal Berakhir */}
Tanggal Berakhir * { if (watchedStartDate && value) { return ( new Date(value) >= new Date(watchedStartDate) || 'Tanggal berakhir harus setelah tanggal mulai' ) } return true } }} render={({ field }) => ( )} />
{/* Status Aktif */}
( } label='Kampanye Aktif' /> )} />
{/* Show on App */}
( } label='Tampilkan di Aplikasi' /> )} />
{/* Tampilkan selengkapnya */} {!showMore && ( )} {/* Konten tambahan */} {showMore && ( <> {/* Description */}
Deskripsi Kampanye ( )} />
{/* Position */}
Posisi Kampanye ( field.onChange(Number(e.target.value))} /> )} />
{/* Sembunyikan */} )}
{/* Sticky Footer */}
) } export default AddEditCampaignDrawer