218 lines
No EOL
7.1 KiB
TypeScript
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>
|
|
);
|
|
} |