freshyo/apps/admin-ui/app/(drawer)/customize-app/index.tsx
2026-01-24 00:13:15 +05:30

218 lines
No EOL
7.1 KiB
TypeScript

import React from 'react';
import { View, ScrollView, Alert } from 'react-native';
import { Formik } from 'formik';
import { MyText, MyTextInput, MyTouchableOpacity, tw, AppContainer, Checkbox } from 'common-ui';
import { trpc } from '../../../src/trpc-client';
import { useRouter } from 'expo-router';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
interface ConstantFormData {
constants: ConstantItem[];
}
interface ConstantItem {
key: string;
value: any;
}
const CONST_LABELS: Record<string, string> = {
minRegularOrderValue: 'Minimum Regular Order Value',
freeDeliveryThreshold: 'Free Delivery Threshold',
deliveryCharge: 'Delivery Charge',
flashFreeDeliveryThreshold: 'Flash Free Delivery Threshold',
flashDeliveryCharge: 'Flash Delivery Charge',
platformFeePercent: 'Platform Fee Percent',
taxRate: 'Tax Rate',
minOrderAmountForCoupon: 'Minimum Order Amount for Coupon',
maxCouponDiscount: 'Maximum Coupon Discount',
flashDeliverySlotId: 'Flash Delivery Slot ID',
readableOrderId: 'Readable Order ID',
versionNum: 'Version Number',
playStoreUrl: 'Play Store URL',
appStoreUrl: 'App Store URL',
popularItems: 'Popular Items',
isFlashDeliveryEnabled: 'Enable Flash Delivery',
supportMobile: 'Support Mobile',
supportEmail: 'Support Email',
};
interface ConstantInputProps {
constant: ConstantItem;
setFieldValue: (field: string, value: any) => void;
index: number;
router: any;
}
const ConstantInput: React.FC<ConstantInputProps> = ({ constant, setFieldValue, index, router }) => {
const fieldName = `constants.${index}.value`;
// Special handling for popularItems - show navigation button instead of input
if (constant.key === 'popularItems') {
return (
<View>
<MyText style={tw`text-sm font-medium text-gray-700 mb-2`}>
{CONST_LABELS[constant.key] || constant.key}
</MyText>
<MyTouchableOpacity
onPress={() => router.push('/(drawer)/customize-app/popular-items')}
style={tw`bg-blue-50 border-2 border-dashed border-blue-200 p-4 rounded-lg flex-row items-center justify-center`}
>
<MaterialIcons name="edit" size={20} color="#3b82f6" style={tw`mr-2`} />
<MyText style={tw`text-blue-700 font-medium`}>
Manage Popular Items ({Array.isArray(constant.value) ? constant.value.length : 0} items)
</MyText>
<MaterialIcons name="chevron-right" size={20} color="#3b82f6" style={tw`ml-2`} />
</MyTouchableOpacity>
</View>
);
}
// Handle boolean values - show checkbox
if (typeof constant.value === 'boolean') {
return (
<View>
<MyText style={tw`text-sm font-medium text-gray-700 mb-2`}>
{CONST_LABELS[constant.key] || constant.key}
</MyText>
<View style={tw`flex-row items-center`}>
<Checkbox
checked={constant.value}
onPress={() => setFieldValue(fieldName, !constant.value)}
size={28}
/>
<MyText style={tw`ml-3 text-gray-700`}>
{constant.value ? 'Enabled' : 'Disabled'}
</MyText>
</View>
</View>
);
}
// Handle different value types
if (typeof constant.value === 'number') {
return (
<MyTextInput
topLabel={CONST_LABELS[constant.key] || constant.key}
value={constant.value.toString()}
onChangeText={(value) => {
const numValue = parseFloat(value);
setFieldValue(fieldName, isNaN(numValue) ? 0 : numValue);
}}
keyboardType="numeric"
placeholder="Enter number"
/>
);
}
if (Array.isArray(constant.value)) {
return (
<MyTextInput
topLabel={CONST_LABELS[constant.key] || constant.key}
value={constant.value.join(', ')}
onChangeText={(value) => {
const arrayValue = value.split(',').map(s => s.trim()).filter(s => s.length > 0);
setFieldValue(fieldName, arrayValue);
}}
placeholder="Enter comma separated values"
/>
);
}
// Default to string
return (
<MyTextInput
topLabel={CONST_LABELS[constant.key] || constant.key}
value={String(constant.value)}
onChangeText={(value) => setFieldValue(fieldName, value)}
placeholder="Enter value"
/>
);
};
export default function CustomizeApp() {
const router = useRouter();
const { data: constants, isLoading: isLoadingConstants, refetch } = trpc.admin.const.getConstants.useQuery();
const { mutate: updateConstants, isPending: isUpdating } = trpc.admin.const.updateConstants.useMutation();
const handleSubmit = (values: ConstantFormData) => {
// Filter out constants that haven't changed
const changedConstants = values.constants.filter((constant, index) => {
const original = constants?.[index];
return original && JSON.stringify(constant.value) !== JSON.stringify(original.value);
});
if (changedConstants.length === 0) {
Alert.alert('No Changes', 'No constants were modified.');
return;
}
updateConstants(
{ constants: changedConstants },
{
onSuccess: (response) => {
Alert.alert('Success', `Updated ${response.updatedCount} constants successfully.`);
refetch();
},
onError: (error) => {
Alert.alert('Error', 'Failed to update constants. Please try again.');
console.error('Update constants error:', error);
},
}
);
};
if (isLoadingConstants) {
return (
<View style={tw`flex-1 justify-center items-center`}>
<MyText style={tw`text-gray-500`}>Loading constants...</MyText>
</View>
);
}
if (!constants) {
return (
<View style={tw`flex-1 justify-center items-center`}>
<MyText style={tw`text-gray-500`}>Failed to load constants</MyText>
</View>
);
}
const initialValues: ConstantFormData = {
constants: constants.map(c => ({ key: c.key, value: c.value ?? '' } as ConstantItem)),
};
return (
<AppContainer>
<View style={tw`flex-1 bg-gray-50 p-4`}>
<MyText style={tw`text-xl font-bold mb-4`}>Customize App Constants</MyText>
<MyText style={tw`text-gray-600 mb-6`}>
Modify application constants. Changes will take effect immediately.
</MyText>
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
{({ handleSubmit, values, setFieldValue }) => (
<View>
{values.constants.map((constant, index) => (
<View key={constant.key} style={tw`mb-4`}>
<ConstantInput constant={constant} setFieldValue={setFieldValue} index={index} router={router} />
</View>
))}
<MyTouchableOpacity
onPress={() => handleSubmit()}
disabled={isUpdating}
style={tw`bg-blue-500 p-4 rounded-lg mt-6 ${isUpdating ? 'opacity-50' : ''}`}
>
<MyText style={tw`text-white text-center font-semibold`}>
{isUpdating ? 'Updating...' : 'Save Changes'}
</MyText>
</MyTouchableOpacity>
</View>
)}
</Formik>
</View>
</AppContainer>
);
}