theme update latest project

This commit is contained in:
Abin Toppo
2026-02-16 10:41:38 +05:30
parent bd7dbd864c
commit a98e0b6cdd
75 changed files with 10173 additions and 7915 deletions
+160 -126
View File
@@ -3,192 +3,226 @@ import {
View,
Text,
StyleSheet,
Alert,
ActivityIndicator,
ScrollView,
KeyboardAvoidingView,
Platform,
TouchableOpacity,
ToastAndroid,
} from "react-native";
import * as Keychain from "react-native-keychain";
import { CustomInput, CustomButton } from "../../components/common/Custom";
import colors from "../../components/colors";
import LucideIcon from '../../components/common/LucideIcon';
import { useNavigation } from "@react-navigation/native";
import { responsiveFontSize } from "react-native-responsive-dimensions";
import { CustomInput, CustomButton } from "../../components/common/Custom";
import { useTheme } from "../../hooks/ui/useTheme";
import { useCreate } from "../../hooks/core/useCreate";
import AppView from "../../components/AppView";
import { Ionicons } from "@react-native-vector-icons/ionicons";
import { BASE_URL } from "../../utils/ApiUrls";
import FontsFamily from "../../constents/FontsFamily";
import { APPLY_ORGANIZER_URL } from "../../utils/ApiUrls";
type OrganizerApplyErrors = {
idName?: string;
idNumber?: string;
issueDate?: string;
};
const isValidIdType = (value: string) => /^[A-Za-z][A-Za-z\s-]{1,}$/.test(value.trim());
const isValidIdNumber = (value: string) => /^[A-Za-z0-9-]{6,24}$/.test(value.trim());
const formatIssueDateInput = (value: string) => {
const digits = value.replace(/\D/g, "").slice(0, 8);
if (digits.length <= 2) return digits;
if (digits.length <= 4) return `${digits.slice(0, 2)}-${digits.slice(2)}`;
return `${digits.slice(0, 2)}-${digits.slice(2, 4)}-${digits.slice(4)}`;
};
const isValidIssueDate = (value: string) => {
if (!/^\d{2}-\d{2}-\d{4}$/.test(value)) return false;
const [day, month, year] = value.split("-").map(Number);
const parsed = new Date(Date.UTC(year, month - 1, day));
const isRealDate =
parsed.getUTCFullYear() === year &&
parsed.getUTCMonth() + 1 === month &&
parsed.getUTCDate() === day;
if (!isRealDate) return false;
const today = new Date();
const todayUtc = Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
return parsed.getTime() <= todayUtc;
};
const BecomeOrg = () => {
const theme = useTheme();
const navigation = useNavigation<any>();
const [idName, setIdName] = useState("");
const [idNumber, setIdNumber] = useState("");
const [issueDate, setIssueDate] = useState("");
const [loading, setLoading] = useState(false);
const [errors, setErrors] = useState<OrganizerApplyErrors>({});
const handleSubmit = async () => {
if (!idName || !idNumber || !issueDate) {
ToastAndroid.show("Please fill all fields", ToastAndroid.SHORT);
return;
}
try {
setLoading(true);
const credentials = await Keychain.getGenericPassword();
if (!credentials) {
ToastAndroid.show("You are not logged in. Please log in to continue.", ToastAndroid.SHORT);
setLoading(false);
// Optionally navigate to login screen
// navigation.navigate("Login");
return;
}
const token = credentials.password;
const response = await fetch(
`${BASE_URL}organizer/registration/apply`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
idName,
idNumber,
issueDate,
}),
}
);
const result = await response.json();
if (response.ok && result.status === "success") {
ToastAndroid.show("Organizer registration application submitted successfully!", ToastAndroid.SHORT);
setIdName("");
setIdNumber("");
setIssueDate("");
navigation.navigate("Home" as never);
const { mutate: applyOrganizer, isPending: loading } = useCreate<any, any>(APPLY_ORGANIZER_URL, {
onSuccess: (res) => {
console.log("api res",res)
if (res.status === "success") {
ToastAndroid.show("Application submitted successfully!", ToastAndroid.SHORT);
navigation.navigate("Home");
} else {
ToastAndroid.show(result.message || "Failed to submit application", ToastAndroid.SHORT);
ToastAndroid.show(res.message || "Failed to submit application", ToastAndroid.SHORT);
}
} catch (error) {
console.error("❌ Registration error:", error);
ToastAndroid.show("An unexpected error occurred. Please try again.", ToastAndroid.SHORT);
} finally {
setLoading(false);
},
onError: (err: any) => {
ToastAndroid.show(err.message || "An error occurred", ToastAndroid.SHORT);
}
});
const handleChange = (field: keyof OrganizerApplyErrors, value: string) => {
if (field === "idName") setIdName(value);
if (field === "idNumber") setIdNumber(value);
if (field === "issueDate") setIssueDate(value);
if (errors[field]) {
setErrors((prev) => ({ ...prev, [field]: "" }));
}
};
const validateForm = () => {
const nextErrors: OrganizerApplyErrors = {};
if (!isValidIdType(idName)) {
nextErrors.idName = "Enter a valid ID type (min 2 letters).";
}
if (!isValidIdNumber(idNumber)) {
nextErrors.idNumber = "ID number must be 6-24 chars (A-Z, 0-9, -).";
}
if (!isValidIssueDate(issueDate)) {
nextErrors.issueDate = "Use valid date DD-MM-YYYY (not future).";
}
setErrors(nextErrors);
return Object.keys(nextErrors).length === 0;
};
const handleSubmit = () => {
if (!validateForm()) {
ToastAndroid.show("Please fix the highlighted fields.", ToastAndroid.SHORT);
return;
}
applyOrganizer({
idName: idName.trim(),
idNumber: idNumber.trim(),
issueDate: issueDate.trim(),
});
};
return (
<AppView barStyle="dark-content">
<AppView keyboardVerticalOffset={60} dismissKeyboardOnTap={false}>
<View style={styles.header}>
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backButton}>
<Ionicons name="arrow-back" size={24} color={'#000'} />
<LucideIcon name="arrow-back" size={24} color={theme.colors.textPrimary} />
</TouchableOpacity>
<Text style={styles.headerTitle}>Become an Organizer</Text>
<View style={styles.placeholder} />
<Text style={[styles.headerTitle, { color: theme.colors.textPrimary }]}>Become Organizer</Text>
</View>
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === "ios" ? "padding" : undefined}
keyboardVerticalOffset={Platform.OS === "ios" ? 60 : 0}
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.scrollContent}
keyboardShouldPersistTaps="handled"
keyboardDismissMode="on-drag"
showsVerticalScrollIndicator={false}
>
<ScrollView
contentContainerStyle={styles.container}
keyboardShouldPersistTaps="handled"
>
<Text style={styles.title}>Submit Your ID for Verification</Text>
<Text style={styles.subtitle}>
<View style={[styles.card, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }]}>
<Text style={[styles.title, { color: theme.colors.textPrimary }]}>ID Verification</Text>
<Text style={[styles.subtitle, { color: theme.colors.textSecondary }]}>
Please provide your official identification details to become a verified organizer.
</Text>
<CustomInput
placeholder="ID Name (e.g., Aadhaar, PAN Card)"
label="ID Type"
placeholder="e.g., Aadhaar, PAN Card"
value={idName}
onChangeText={setIdName}
onChangeText={(val) => handleChange("idName", val)}
icon="person-outline"
error={""}
error={errors.idName}
/>
<CustomInput
placeholder="ID Number"
label="ID Number"
placeholder="Enter your ID number"
value={idNumber}
onChangeText={setIdNumber}
onChangeText={(val) => handleChange("idNumber", val.toUpperCase())}
autoCapitalize="characters"
icon="card-outline"
error=""
error={errors.idNumber}
/>
<CustomInput
placeholder="Issue Date (YYYY-MM-DD)"
label="Issue Date"
placeholder="DD-MM-YYYY"
value={issueDate}
onChangeText={setIssueDate}
onChangeText={(val) => handleChange("issueDate", formatIssueDateInput(val))}
icon="calendar-outline"
error=""
error={errors.issueDate}
/>
<CustomButton
title={loading ? "Submitting..." : "Request Organizer Role"}
title="Submit Application"
onPress={handleSubmit}
loading={loading}
style={styles.submitBtn}
icon="send-outline"
buttonBackground={colors.pastelBlue}
style={{ opacity: loading ? 0.6 : 1, marginTop: 20 }}
/>
{loading && (
<ActivityIndicator
style={{ marginTop: 15 }}
size="large"
color={colors.primary}
/>
)}
</ScrollView>
</KeyboardAvoidingView>
</View>
</ScrollView>
</AppView>
);
};
export default BecomeOrg;
const styles = StyleSheet.create({
container: {
flexGrow: 1,
padding: 20,
justifyContent: "center",
},
title: {
fontSize: 24,
fontWeight: "700",
marginBottom: 10,
textAlign: "center",
color: colors.textDark,
},
subtitle: {
fontSize: 16,
textAlign: "center",
color: colors.textDark,
marginBottom: 30,
},
header: {
flexDirection: "row",
alignItems: "center",
paddingHorizontal: 16,
paddingVertical: 12,
backgroundColor: '#FFF',
borderBottomWidth: 1,
borderBottomColor: '#E0E0E0',
paddingHorizontal: 24,
paddingVertical: 16,
},
backButton: {
padding: 5,
marginRight: 16,
padding: 4,
},
headerTitle: {
fontSize: responsiveFontSize(2.4),
fontFamily: FontsFamily.nunitoBold,
},
scrollView: {
flex: 1,
fontSize: 20,
fontWeight: "600",
color: "#000",
},
scrollContent: {
flexGrow: 1,
paddingHorizontal: 20,
paddingTop: 10,
justifyContent: "flex-start",
paddingBottom: 40,
},
card: {
padding: 24,
borderRadius: 24,
borderWidth: 1,
elevation: 2,
shadowColor: '#000',
shadowOpacity: 0.04,
shadowRadius: 12,
shadowOffset: { width: 0, height: 4 },
},
title: {
fontSize: responsiveFontSize(2.6),
fontFamily: FontsFamily.nunitoBold,
marginBottom: 8,
textAlign: "center",
},
placeholder: {
width: 24, // to balance the back button
subtitle: {
fontSize: responsiveFontSize(1.6),
fontFamily: FontsFamily.nunitoRegular,
textAlign: "center",
marginBottom: 30,
},
submitBtn: {
marginTop: 12,
}
});
export default BecomeOrg;