| 1 | /** |
| 2 | * CreatePlanModal - 创建/编辑草稿弹窗 |
| 3 | * 仅包含名称输入 |
| 4 | */ |
| 5 | |
| 6 | 'use client' |
| 7 | |
| 8 | import { Loader2 } from 'lucide-react' |
| 9 | import { useCallback, useEffect, useState } from 'react' |
| 10 | import { useShallow } from 'zustand/react/shallow' |
| 11 | import { useTransClient } from '@/app/i18n/client' |
| 12 | import { Button } from '@/components/ui/button' |
| 13 | import { |
| 14 | Dialog, |
| 15 | DialogContent, |
| 16 | DialogFooter, |
| 17 | DialogHeader, |
| 18 | DialogTitle, |
| 19 | } from '@/components/ui/dialog' |
| 20 | import { Input } from '@/components/ui/input' |
| 21 | import { Label } from '@/components/ui/label' |
| 22 | import { useBrandPromotionStore } from '@/store/draft-box/brandPromotionStore' |
| 23 | import { toast } from '@/utils/ui/toast' |
| 24 | |
| 25 | function CreatePlanModal() { |
| 26 | const { t } = useTransClient('brandPromotion') |
| 27 | |
| 28 | const { |
| 29 | createPlanModalOpen, |
| 30 | editingPlan, |
| 31 | isSubmitting, |
| 32 | closePlanModal, |
| 33 | createPlan, |
| 34 | updatePlan, |
| 35 | } = useBrandPromotionStore( |
| 36 | useShallow(state => ({ |
| 37 | createPlanModalOpen: state.createPlanModalOpen, |
| 38 | editingPlan: state.editingPlan, |
| 39 | isSubmitting: state.isSubmitting, |
| 40 | closePlanModal: state.closePlanModal, |
| 41 | createPlan: state.createPlan, |
| 42 | updatePlan: state.updatePlan, |
| 43 | })), |
| 44 | ) |
| 45 | |
| 46 | const isEdit = editingPlan !== null |
| 47 | |
| 48 | // 表单状态 |
| 49 | const [name, setName] = useState('') |
| 50 | |
| 51 | // 初始化/重置表单 |
| 52 | useEffect(() => { |
| 53 | if (createPlanModalOpen) { |
| 54 | if (editingPlan) { |
| 55 | setName(editingPlan.name || editingPlan.title || '') |
| 56 | } |
| 57 | else { |
| 58 | setName('') |
| 59 | } |
| 60 | } |
| 61 | }, [createPlanModalOpen, editingPlan]) |
| 62 | |
| 63 | const handleSubmit = useCallback(async () => { |
| 64 | if (!name.trim()) |
| 65 | return |
| 66 | |
| 67 | if (isEdit && editingPlan) { |
| 68 | const success = await updatePlan(editingPlan.id, { |
| 69 | name: name.trim(), |
| 70 | }) |
| 71 | if (success) { |
| 72 | toast.success(t('createPlan.updateSuccess')) |
| 73 | closePlanModal() |
| 74 | } |
| 75 | else { |
| 76 | toast.error(t('createPlan.updateFailed')) |
| 77 | } |
| 78 | } |
| 79 | else { |
| 80 | const success = await createPlan({ |
| 81 | name: name.trim(), |
| 82 | }) |
| 83 | if (success) { |
| 84 | toast.success(t('createPlan.createSuccess')) |
| 85 | closePlanModal() |
| 86 | } |
| 87 | else { |
| 88 | toast.error(t('createPlan.createFailed')) |
| 89 | } |
| 90 | } |
| 91 | }, [name, isEdit, editingPlan, createPlan, updatePlan, closePlanModal, t]) |
| 92 | |
| 93 | if (!createPlanModalOpen) { |
| 94 | return null |
| 95 | } |
| 96 | |
| 97 | return ( |
| 98 | <Dialog |
| 99 | open={createPlanModalOpen} |
| 100 | onOpenChange={(open) => { |
| 101 | if (!open) |
| 102 | closePlanModal() |
| 103 | }} |
| 104 | > |
| 105 | <DialogContent className="sm:w-[min(500px,95vw)]"> |
| 106 | <DialogHeader> |
| 107 | <DialogTitle> |
| 108 | {isEdit ? t('createPlan.editTitle') : t('createPlan.title')} |
| 109 | </DialogTitle> |
| 110 | </DialogHeader> |
| 111 | |
| 112 | <div className="space-y-4 py-2"> |
| 113 | {/* 名称 */} |
| 114 | <div className="space-y-2"> |
| 115 | <Label>{t('createPlan.name')}</Label> |
| 116 | <Input |
| 117 | value={name} |
| 118 | onChange={e => setName(e.target.value)} |
| 119 | placeholder={t('createPlan.namePlaceholder')} |
| 120 | maxLength={50} |
| 121 | /> |
| 122 | </div> |
| 123 | </div> |
| 124 | |
| 125 | <DialogFooter> |
| 126 | <Button |
| 127 | variant="outline" |
| 128 | onClick={closePlanModal} |
| 129 | disabled={isSubmitting} |
| 130 | className="cursor-pointer" |
| 131 | > |
| 132 | {t('common.cancel')} |
| 133 | </Button> |
| 134 | <Button |
| 135 | onClick={handleSubmit} |
| 136 | disabled={isSubmitting || !name.trim()} |
| 137 | className="cursor-pointer" |
| 138 | > |
| 139 | {isSubmitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} |
| 140 | {isEdit ? t('common.save') : t('common.confirm')} |
| 141 | </Button> |
| 142 | </DialogFooter> |
| 143 | </DialogContent> |
| 144 | </Dialog> |
| 145 | ) |
| 146 | } |
| 147 | |
| 148 | export default CreatePlanModal |
| 149 |