222 lines
No EOL
7.6 KiB
TypeScript
222 lines
No EOL
7.6 KiB
TypeScript
import React from 'react';
|
|
import { View, Text, TouchableOpacity, Alert } from 'react-native';
|
|
import { Formik, FieldArray } from 'formik';
|
|
import DateTimePickerMod from 'common-ui/src/components/date-time-picker';
|
|
import { tw, MyTextInput } from 'common-ui';
|
|
import { trpc } from '../src/trpc-client';
|
|
import ProductsSelector from '../components/ProductsSelector';
|
|
|
|
interface VendorSnippet {
|
|
name: string;
|
|
groupIds: number[];
|
|
productIds: number[];
|
|
validTill?: string;
|
|
}
|
|
|
|
interface SlotFormProps {
|
|
onSlotAdded?: () => void;
|
|
initialDeliveryTime?: Date | null;
|
|
initialFreezeTime?: Date | null;
|
|
initialIsActive?: boolean;
|
|
slotId?: number;
|
|
initialProductIds?: number[];
|
|
}
|
|
|
|
export default function SlotForm({
|
|
onSlotAdded,
|
|
initialDeliveryTime,
|
|
initialFreezeTime,
|
|
initialIsActive = true,
|
|
slotId,
|
|
initialProductIds = [],
|
|
}: SlotFormProps) {
|
|
const initialValues = {
|
|
deliveryTime: initialDeliveryTime || null,
|
|
freezeTime: initialFreezeTime || null,
|
|
selectedGroupIds: [] as number[],
|
|
selectedProductIds: initialProductIds,
|
|
vendorSnippetList: [] as VendorSnippet[],
|
|
};
|
|
|
|
const { mutate: createSlot, isPending: isCreating } = trpc.admin.slots.createSlot.useMutation();
|
|
const { mutate: updateSlot, isPending: isUpdating } = trpc.admin.slots.updateSlot.useMutation();
|
|
|
|
const isEditMode = !!slotId;
|
|
const isPending = isCreating || isUpdating;
|
|
|
|
// Fetch groups
|
|
const { data: groupsData } = trpc.admin.product.getGroups.useQuery();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleFormSubmit = (values: typeof initialValues) => {
|
|
if (!values.deliveryTime || !values.freezeTime) {
|
|
Alert.alert('Error', 'Please fill all fields');
|
|
return;
|
|
}
|
|
|
|
const slotData = {
|
|
deliveryTime: values.deliveryTime.toISOString(),
|
|
freezeTime: values.freezeTime.toISOString(),
|
|
isActive: initialIsActive,
|
|
productIds: values.selectedProductIds,
|
|
vendorSnippets: values.vendorSnippetList.map(snippet => ({
|
|
name: snippet.name,
|
|
productIds: snippet.productIds,
|
|
validTill: snippet.validTill,
|
|
})),
|
|
};
|
|
|
|
console.log({snippetList: values.vendorSnippetList})
|
|
|
|
values.vendorSnippetList.forEach((snippet, index) => {
|
|
console.log({snippet})
|
|
|
|
});
|
|
|
|
|
|
if (isEditMode && slotId) {
|
|
updateSlot(
|
|
{ id: slotId, ...slotData },
|
|
{
|
|
onSuccess: () => {
|
|
Alert.alert('Success', 'Slot updated successfully!');
|
|
onSlotAdded?.();
|
|
},
|
|
onError: (error: any) => {
|
|
console.log({msg: JSON.stringify(error.message)})
|
|
|
|
Alert.alert('Error', error.message || 'Failed to update slot');
|
|
},
|
|
}
|
|
);
|
|
} else {
|
|
createSlot(
|
|
slotData,
|
|
{
|
|
onSuccess: () => {
|
|
Alert.alert('Success', 'Slot created successfully!');
|
|
// Reset form
|
|
// Formik will handle reset
|
|
onSlotAdded?.();
|
|
},
|
|
onError: (error: any) => {
|
|
Alert.alert('Error', error.message || 'Failed to create slot');
|
|
},
|
|
}
|
|
);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Formik
|
|
initialValues={initialValues}
|
|
onSubmit={handleFormSubmit}
|
|
>
|
|
{({ handleSubmit, values, setFieldValue }) => {
|
|
// Map groups data to match ProductsSelector types (convert price from string to number)
|
|
const mappedGroups = (groupsData?.groups || []).map(group => ({
|
|
...group,
|
|
products: group.products.map(product => ({
|
|
...product,
|
|
price: parseFloat(product.price as unknown as string) || 0,
|
|
})),
|
|
}));
|
|
|
|
return (
|
|
<View style={tw`mb-4`}>
|
|
<Text style={tw`text-xl font-bold mb-6 text-center`}>
|
|
{isEditMode ? 'Edit Slot' : 'Create New Slot'}
|
|
</Text>
|
|
|
|
<View style={tw`mb-4`}>
|
|
<Text style={tw`text-lg font-semibold mb-2`}>Delivery Date & Time</Text>
|
|
<DateTimePickerMod value={values.deliveryTime} setValue={(value) => setFieldValue('deliveryTime', value)} />
|
|
</View>
|
|
|
|
<View style={tw`mb-4`}>
|
|
<Text style={tw`text-lg font-semibold mb-2`}>Freeze Date & Time</Text>
|
|
<DateTimePickerMod value={values.freezeTime} setValue={(value) => setFieldValue('freezeTime', value)} />
|
|
</View>
|
|
|
|
<View style={tw`mb-4`}>
|
|
<ProductsSelector
|
|
value={values.selectedProductIds}
|
|
onChange={(newProductIds) => setFieldValue('selectedProductIds', newProductIds)}
|
|
groups={mappedGroups}
|
|
selectedGroupIds={values.selectedGroupIds}
|
|
onGroupChange={(newGroupIds) => setFieldValue('selectedGroupIds', newGroupIds)}
|
|
label="Select Products"
|
|
placeholder="Select products for this slot"
|
|
/>
|
|
</View>
|
|
|
|
{/* Vendor Snippets */}
|
|
<FieldArray name="vendorSnippetList">
|
|
{({ push, remove }) => (
|
|
<View style={tw`mb-4`}>
|
|
<Text style={tw`text-lg font-semibold mb-4`}>Vendor Snippets</Text>
|
|
{values.vendorSnippetList.map((snippet, index) => (
|
|
<View key={index} style={tw`bg-gray-50 p-4 rounded-lg mb-4`}>
|
|
<View style={tw`mb-4`}>
|
|
<MyTextInput
|
|
topLabel="Snippet Name *"
|
|
placeholder="Enter snippet name"
|
|
value={snippet.name}
|
|
onChangeText={(text) => setFieldValue(`vendorSnippetList.${index}.name`, text)}
|
|
/>
|
|
</View>
|
|
|
|
<View style={tw`mb-4`}>
|
|
<ProductsSelector
|
|
value={snippet.productIds || []}
|
|
onChange={(newProductIds) => setFieldValue(`vendorSnippetList.${index}.productIds`, newProductIds)}
|
|
groups={mappedGroups.filter(group =>
|
|
values.selectedGroupIds.includes(group.id)
|
|
).map(group => ({
|
|
...group,
|
|
products: group.products.filter(p => values.selectedProductIds.includes(p.id))
|
|
}))}
|
|
selectedGroupIds={snippet.groupIds || []}
|
|
onGroupChange={(newGroupIds) => setFieldValue(`vendorSnippetList.${index}.groupIds`, newGroupIds)}
|
|
label="Select Products"
|
|
placeholder="Select products for snippet"
|
|
isDisabled={(product) => !values.selectedProductIds.includes(product.id)}
|
|
/>
|
|
</View>
|
|
<TouchableOpacity
|
|
onPress={() => remove(index)}
|
|
style={tw`bg-red-500 px-4 py-2 rounded-lg self-end`}
|
|
>
|
|
<Text style={tw`text-white font-medium`}>Remove Snippet</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
))}
|
|
<TouchableOpacity
|
|
onPress={() => push({ name: '', groupIds: [], productIds: [], validTill: '' })}
|
|
style={tw`bg-blue-500 px-4 py-3 rounded-lg items-center`}
|
|
>
|
|
<Text style={tw`text-white font-medium`}>Add Vendor Snippet</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
)}
|
|
</FieldArray>
|
|
|
|
<TouchableOpacity
|
|
onPress={() => handleSubmit()}
|
|
disabled={isPending}
|
|
style={tw`${isPending ? 'bg-pink2' : 'bg-pink1'} p-3 rounded-lg items-center mt-6 pb-4`}
|
|
>
|
|
<Text style={tw`text-white text-base font-bold`}>
|
|
{isPending ? (isEditMode ? 'Updating...' : 'Creating...') : (isEditMode ? 'Update Slot' : 'Create Slot')}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
)}}
|
|
</Formik>
|
|
);
|
|
} |