151 lines
No EOL
4.7 KiB
TypeScript
151 lines
No EOL
4.7 KiB
TypeScript
import React from 'react';
|
|
import { View, TouchableOpacity, Alert, ScrollView } from 'react-native';
|
|
import { useFormik } from 'formik';
|
|
import { MyText, tw, MyTextInput, MyTouchableOpacity, theme, BottomDropdown } from 'common-ui';
|
|
import { trpc } from '../src/trpc-client';
|
|
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
|
|
|
interface ProductGroup {
|
|
id: number;
|
|
groupName: string;
|
|
description: string | null;
|
|
createdAt: string;
|
|
products: any[];
|
|
productCount: number;
|
|
}
|
|
|
|
interface ProductGroupFormProps {
|
|
group?: ProductGroup | null;
|
|
onClose: () => void;
|
|
onSuccess: () => void;
|
|
}
|
|
|
|
const ProductGroupForm: React.FC<ProductGroupFormProps> = ({
|
|
group,
|
|
onClose,
|
|
onSuccess,
|
|
}) => {
|
|
// Fetch products
|
|
const { data: productsData } = trpc.common.product.getAllProductsSummary.useQuery({});
|
|
|
|
const createGroup = trpc.admin.product.createGroup.useMutation();
|
|
const updateGroup = trpc.admin.product.updateGroup.useMutation();
|
|
|
|
const isEditing = !!group;
|
|
|
|
const products = productsData?.products || [];
|
|
|
|
const productOptions = products.map(product => ({
|
|
label: `${product.name}${product.shortDescription ? ` - ${product.shortDescription}` : ''}`,
|
|
value: product.id,
|
|
}));
|
|
|
|
const formik = useFormik({
|
|
initialValues: {
|
|
group_name: group?.groupName || '',
|
|
description: group?.description || '',
|
|
product_ids: group?.products?.map(p => p.id) || [],
|
|
},
|
|
validate: (values) => {
|
|
const errors: {[key: string]: string} = {};
|
|
|
|
if (!values.group_name.trim()) {
|
|
errors.group_name = 'Group name is required';
|
|
}
|
|
|
|
return errors;
|
|
},
|
|
onSubmit: async (values) => {
|
|
try {
|
|
if (isEditing) {
|
|
await updateGroup.mutateAsync({
|
|
id: group.id,
|
|
group_name: values.group_name,
|
|
description: values.description,
|
|
product_ids: values.product_ids,
|
|
});
|
|
} else {
|
|
await createGroup.mutateAsync({
|
|
group_name: values.group_name,
|
|
description: values.description,
|
|
product_ids: values.product_ids,
|
|
});
|
|
}
|
|
onSuccess();
|
|
} catch (error: any) {
|
|
Alert.alert('Error', error.message || 'Failed to save group');
|
|
}
|
|
},
|
|
});
|
|
|
|
return (
|
|
<View style={tw`flex-1 bg-white`}>
|
|
{/* Header */}
|
|
<View style={tw`flex-row items-center justify-between p-6 border-b border-gray-200`}>
|
|
<MyText style={tw`text-xl font-bold text-gray-900`}>
|
|
{isEditing ? 'Edit Product Group' : 'Create Product Group'}
|
|
</MyText>
|
|
<TouchableOpacity onPress={onClose} style={tw`p-2`}>
|
|
<MaterialIcons name="close" size={24} color="#6B7280" />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<ScrollView style={tw`flex-1`} contentContainerStyle={tw`px-6 py-4`}>
|
|
{/* Group Name */}
|
|
<MyTextInput
|
|
topLabel="Group Name *"
|
|
placeholder="Enter group name"
|
|
value={formik.values.group_name}
|
|
onChangeText={(text) => formik.setFieldValue('group_name', text)}
|
|
style={{ marginBottom: 16 }}
|
|
/>
|
|
{formik.errors.group_name && (
|
|
<MyText style={tw`text-red-500 text-sm mt-1 mb-4`}>{formik.errors.group_name}</MyText>
|
|
)}
|
|
|
|
{/* Description */}
|
|
<MyTextInput
|
|
topLabel="Description"
|
|
placeholder="Enter description (optional)"
|
|
multiline
|
|
numberOfLines={3}
|
|
value={formik.values.description}
|
|
onChangeText={(text) => formik.setFieldValue('description', text)}
|
|
style={{ marginBottom: 16 }}
|
|
/>
|
|
|
|
{/* Products Selection */}
|
|
<BottomDropdown
|
|
label="Products"
|
|
value={formik.values.product_ids}
|
|
options={productOptions}
|
|
onValueChange={(value) => formik.setFieldValue('product_ids', value as number[])}
|
|
multiple={true}
|
|
placeholder="Select products"
|
|
style={{ marginBottom: 16 }}
|
|
/>
|
|
|
|
{/* Actions */}
|
|
<View style={tw`flex-row gap-4`}>
|
|
<MyTouchableOpacity
|
|
onPress={onClose}
|
|
style={tw`flex-1 bg-gray-200 rounded-lg py-4 items-center`}
|
|
>
|
|
<MyText style={tw`text-gray-700 font-medium`}>Cancel</MyText>
|
|
</MyTouchableOpacity>
|
|
<MyTouchableOpacity
|
|
onPress={() => formik.handleSubmit()}
|
|
disabled={createGroup.isPending || updateGroup.isPending}
|
|
style={tw`flex-1 bg-brand600 rounded-lg py-4 items-center`}
|
|
>
|
|
<MyText style={tw`text-white font-medium`}>
|
|
{createGroup.isPending || updateGroup.isPending ? 'Saving...' : 'Save'}
|
|
</MyText>
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
</ScrollView>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default ProductGroupForm; |