290 lines
12 KiB
TypeScript
290 lines
12 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { PackageName, CreatePackageData, UpdatePackageData } from '@/types/package';
|
|
import { XMarkIcon, PhotoIcon, DocumentTextIcon } from '@heroicons/react/24/outline';
|
|
|
|
interface PackageFormProps {
|
|
package?: PackageName | null;
|
|
onSubmit: (data: CreatePackageData | UpdatePackageData) => Promise<void>;
|
|
onCancel: () => void;
|
|
isLoading: boolean;
|
|
}
|
|
|
|
export default function PackageForm({ package: pkg, onSubmit, onCancel, isLoading }: PackageFormProps) {
|
|
const [formData, setFormData] = useState<CreatePackageData | UpdatePackageData>({
|
|
name: '',
|
|
title: '',
|
|
v1_identifier: '',
|
|
myket_access_token: '',
|
|
cafe_config_id: null,
|
|
web_app_url: '',
|
|
tries: 0,
|
|
});
|
|
|
|
const [avatarFile, setAvatarFile] = useState<File | null>(null);
|
|
const [firebaseFile, setFirebaseFile] = useState<File | null>(null);
|
|
const [avatarPreview, setAvatarPreview] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (pkg) {
|
|
setFormData({
|
|
name: pkg.name || '',
|
|
title: pkg.title || '',
|
|
v1_identifier: pkg.v1_identifier || '',
|
|
myket_access_token: pkg.myket_access_token || '',
|
|
cafe_config_id: pkg.cafe_config_id,
|
|
web_app_url: pkg.web_app_url || '',
|
|
tries: pkg.tries || 0,
|
|
});
|
|
|
|
if (pkg.image && typeof pkg.image === 'string') {
|
|
setAvatarPreview(pkg.image);
|
|
}
|
|
}
|
|
}, [pkg]);
|
|
|
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
const { name, value } = e.target;
|
|
setFormData(prev => ({
|
|
...prev,
|
|
[name]: value === '' ? null : value,
|
|
}));
|
|
};
|
|
|
|
const handleNumberChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const { name, value } = e.target;
|
|
setFormData(prev => ({
|
|
...prev,
|
|
[name]: value === '' ? null : parseInt(value, 10),
|
|
}));
|
|
};
|
|
|
|
const handleAvatarChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const file = e.target.files?.[0];
|
|
if (file) {
|
|
setAvatarFile(file);
|
|
setFormData(prev => ({ ...prev, avatar: file }));
|
|
|
|
// Create preview
|
|
const reader = new FileReader();
|
|
reader.onloadend = () => {
|
|
setAvatarPreview(reader.result as string);
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
};
|
|
|
|
const handleFirebaseChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const file = e.target.files?.[0];
|
|
if (file) {
|
|
setFirebaseFile(file);
|
|
setFormData(prev => ({ ...prev, firebase_json: file }));
|
|
}
|
|
};
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
await onSubmit(formData);
|
|
};
|
|
|
|
const removeAvatar = () => {
|
|
setAvatarFile(null);
|
|
setAvatarPreview(null);
|
|
setFormData(prev => ({ ...prev, avatar: null }));
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit} className="space-y-6 bg-white p-6 rounded-lg shadow">
|
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
{/* Name */}
|
|
<div>
|
|
<label htmlFor="name" className="block text-sm font-medium text-gray-700 mb-1">
|
|
نام پکیج <span className="text-red-500">*</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="name"
|
|
name="name"
|
|
required
|
|
value={formData.name || ''}
|
|
onChange={handleInputChange}
|
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
|
placeholder="مثال: com.approagency.meditation"
|
|
dir="ltr"
|
|
/>
|
|
</div>
|
|
|
|
{/* Title */}
|
|
<div>
|
|
<label htmlFor="title" className="block text-sm font-medium text-gray-700 mb-1">
|
|
عنوان <span className="text-red-500">*</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="title"
|
|
name="title"
|
|
required
|
|
value={formData.title || ''}
|
|
onChange={handleInputChange}
|
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
|
placeholder="مثال: آرام لند"
|
|
/>
|
|
</div>
|
|
|
|
{/* Avatar */}
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
تصویر
|
|
</label>
|
|
<div className="flex items-center space-x-3 space-x-reverse">
|
|
<label className="cursor-pointer flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
|
|
<PhotoIcon className="h-5 w-5 ml-2 text-gray-400" />
|
|
انتخاب تصویر
|
|
<input
|
|
type="file"
|
|
accept="image/*"
|
|
onChange={handleAvatarChange}
|
|
className="hidden"
|
|
/>
|
|
</label>
|
|
{avatarPreview && (
|
|
<button
|
|
type="button"
|
|
onClick={removeAvatar}
|
|
className="text-red-600 hover:text-red-900"
|
|
>
|
|
<XMarkIcon className="h-5 w-5" />
|
|
</button>
|
|
)}
|
|
</div>
|
|
{avatarPreview && (
|
|
<div className="mt-2">
|
|
<img
|
|
src={avatarPreview}
|
|
alt="Preview"
|
|
className="h-20 w-20 object-cover rounded-lg border border-gray-200"
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* V1 Identifier */}
|
|
<div>
|
|
<label htmlFor="v1_identifier" className="block text-sm font-medium text-gray-700 mb-1">
|
|
شناسه V1
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="v1_identifier"
|
|
name="v1_identifier"
|
|
value={formData.v1_identifier || ''}
|
|
onChange={handleInputChange}
|
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
|
/>
|
|
</div>
|
|
|
|
{/* Myket Access Token */}
|
|
<div>
|
|
<label htmlFor="myket_access_token" className="block text-sm font-medium text-gray-700 mb-1">
|
|
توکن دسترسی Myket
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="myket_access_token"
|
|
name="myket_access_token"
|
|
value={formData.myket_access_token || ''}
|
|
onChange={handleInputChange}
|
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
|
/>
|
|
</div>
|
|
|
|
{/* Cafe Config ID */}
|
|
<div>
|
|
<label htmlFor="cafe_config_id" className="block text-sm font-medium text-gray-700 mb-1">
|
|
شناسه کافه بازار
|
|
</label>
|
|
<input
|
|
type="number"
|
|
id="cafe_config_id"
|
|
name="cafe_config_id"
|
|
value={formData.cafe_config_id || ''}
|
|
onChange={handleNumberChange}
|
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
|
/>
|
|
</div>
|
|
|
|
{/* Web App URL */}
|
|
<div>
|
|
<label htmlFor="web_app_url" className="block text-sm font-medium text-gray-700 mb-1">
|
|
آدرس وب اپلیکیشن
|
|
</label>
|
|
<input
|
|
type="url"
|
|
id="web_app_url"
|
|
name="web_app_url"
|
|
value={formData.web_app_url || ''}
|
|
onChange={handleInputChange}
|
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
|
placeholder="https://example.com"
|
|
/>
|
|
</div>
|
|
|
|
{/* Tries */}
|
|
<div>
|
|
<label htmlFor="tries" className="block text-sm font-medium text-gray-700 mb-1">
|
|
تعداد تلاشها
|
|
</label>
|
|
<input
|
|
type="number"
|
|
id="tries"
|
|
name="tries"
|
|
value={formData.tries || 0}
|
|
onChange={handleNumberChange}
|
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
|
/>
|
|
</div>
|
|
|
|
{/* Firebase JSON */}
|
|
<div className="md:col-span-2">
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
فایل Firebase JSON
|
|
</label>
|
|
<label className="cursor-pointer inline-flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
|
|
<DocumentTextIcon className="h-5 w-5 ml-2 text-gray-400" />
|
|
انتخاب فایل
|
|
<input
|
|
type="file"
|
|
accept=".json,application/json"
|
|
onChange={handleFirebaseChange}
|
|
className="hidden"
|
|
/>
|
|
</label>
|
|
{firebaseFile && (
|
|
<p className="mt-2 text-sm text-gray-600">
|
|
فایل انتخاب شده: {firebaseFile.name}
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Form Actions */}
|
|
<div className="flex justify-end space-x-3 space-x-reverse pt-4 border-t">
|
|
<button
|
|
type="button"
|
|
onClick={onCancel}
|
|
className="px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
>
|
|
انصراف
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
disabled={isLoading}
|
|
className="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50"
|
|
>
|
|
{isLoading ? 'در حال ذخیره...' : pkg ? 'بهروزرسانی' : 'ایجاد'}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
);
|
|
} |