@adminide-stack/yantra-mobile 12.0.73 → 12.0.74-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,85 +1,22 @@
1
- import {jsxs,jsx,Fragment}from'react/jsx-runtime';import React__default from'react';import {StyleSheet,Platform,View,TouchableOpacity,Text,ScrollView,ActivityIndicator,TextInput,Modal}from'react-native';import {SafeAreaView}from'react-native-safe-area-context';import {Ionicons}from'@expo/vector-icons';import {usePhoneVerification,isChatTestOtpEnabled,CHAT_REGISTRATION_TEST_OTP}from'./usePhoneVerification.js';const ALL_COUNTRIES = [{
2
- code: "US",
3
- name: "United States",
4
- callingCode: "+1"
5
- }, {
6
- code: "IN",
7
- name: "India",
8
- callingCode: "+91"
9
- }, {
10
- code: "PK",
11
- name: "Pakistan",
12
- callingCode: "+92"
13
- }, {
14
- code: "BD",
15
- name: "Bangladesh",
16
- callingCode: "+880"
17
- }, {
18
- code: "AE",
19
- name: "United Arab Emirates",
20
- callingCode: "+971"
21
- }, {
22
- code: "GB",
23
- name: "United Kingdom",
24
- callingCode: "+44"
25
- }, {
26
- code: "CA",
27
- name: "Canada",
28
- callingCode: "+1"
29
- }, {
30
- code: "AU",
31
- name: "Australia",
32
- callingCode: "+61"
33
- }, {
34
- code: "FR",
35
- name: "France",
36
- callingCode: "+33"
37
- }, {
38
- code: "DE",
39
- name: "Germany",
40
- callingCode: "+49"
41
- }, {
42
- code: "ES",
43
- name: "Spain",
44
- callingCode: "+34"
45
- }, {
46
- code: "IT",
47
- name: "Italy",
48
- callingCode: "+39"
49
- }, {
50
- code: "BR",
51
- name: "Brazil",
52
- callingCode: "+55"
53
- }, {
54
- code: "MX",
55
- name: "Mexico",
56
- callingCode: "+52"
57
- }, {
58
- code: "SG",
59
- name: "Singapore",
60
- callingCode: "+65"
61
- }, {
62
- code: "JP",
63
- name: "Japan",
64
- callingCode: "+81"
65
- }, {
66
- code: "CN",
67
- name: "China",
68
- callingCode: "+86"
69
- }];
70
- const DEFAULT_ALLOWED_DIAL_CODES = ["+1"];
71
- function allowedDialCodes(raw = process.env.EXPO_PUBLIC_PHONE_OTP_ALLOWED_DIAL_CODES) {
72
- const value = raw == null ? void 0 : raw.trim();
73
- if (value === "*") return null;
74
- if (!value) return DEFAULT_ALLOWED_DIAL_CODES;
75
- const codes = value.split(",").map((c) => c.trim()).filter(Boolean).map((c) => c.startsWith("+") ? c : `+${c}`);
76
- return codes.length ? codes : DEFAULT_ALLOWED_DIAL_CODES;
77
- }
78
- function pickerCountries(all = ALL_COUNTRIES, allowed = allowedDialCodes()) {
79
- if (!allowed) return all;
80
- const offered = all.filter((c) => allowed.includes(c.callingCode));
81
- return offered.length ? offered : [all[0]];
82
- }
1
+ import {jsxs,jsx,Fragment}from'react/jsx-runtime';import React__default from'react';import {StyleSheet,Platform,View,TouchableOpacity,Text,ScrollView,ActivityIndicator,Modal,TextInput,FlatList}from'react-native';import {SafeAreaView}from'react-native-safe-area-context';import {Ionicons}from'@expo/vector-icons';import {usePhoneVerification,isChatTestOtpEnabled,CHAT_REGISTRATION_TEST_OTP}from'./usePhoneVerification.js';import {pickerCountries,filterCountries,countryFlag}from'./countryPicker.js';import {sanitizePhoneInput}from'./mobileNumberCheck.js';var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
83
20
  const COUNTRIES = pickerCountries();
84
21
  function PhoneRow({
85
22
  countryCode,
@@ -90,39 +27,85 @@ function PhoneRow({
90
27
  disabled,
91
28
  theme
92
29
  }) {
93
- var _a;
30
+ var _a, _b;
31
+ const [focused, setFocused] = React__default.useState(false);
94
32
  return /* @__PURE__ */ jsxs(View, { style: [styles.phoneRow, {
95
- flexDirection: "row",
96
- alignItems: "center",
97
- borderColor: theme.colors.border,
33
+ borderColor: focused ? theme.colors.primary : theme.colors.border,
34
+ borderWidth: focused ? 2 : 1,
98
35
  backgroundColor: (_a = theme.colors.card) != null ? _a : "#fff"
99
36
  }], children: [
100
37
  /* @__PURE__ */ jsxs(TouchableOpacity, { onPress: onCountryPress, disabled, style: [styles.countryChip, {
101
- flexDirection: "row",
102
- alignItems: "center"
103
- }], accessibilityRole: "button", accessibilityLabel: "Select country code", children: [
38
+ backgroundColor: `${theme.colors.primary}12`
39
+ }], accessibilityRole: "button", accessibilityLabel: `Country code ${callingCode}. Change country`, testID: "chat-registration-country", children: [
40
+ /* @__PURE__ */ jsx(Text, { style: styles.countryChipFlag, children: countryFlag(countryCode) }),
104
41
  /* @__PURE__ */ jsx(Text, { style: [styles.callingCode, {
105
42
  color: theme.colors.text
106
43
  }], children: callingCode }),
107
- /* @__PURE__ */ jsx(Ionicons, { name: "chevron-down", size: 18, color: theme.colors.textSecondary })
44
+ /* @__PURE__ */ jsx(Ionicons, { name: "chevron-down", size: 16, color: theme.colors.textSecondary })
108
45
  ] }),
109
- /* @__PURE__ */ jsx(View, { style: [styles.phoneDivider, {
110
- backgroundColor: theme.colors.border
111
- }] }),
112
46
  /* @__PURE__ */ jsx(TextInput, { style: [styles.phoneInput, {
113
47
  color: theme.colors.text
114
- }], placeholder: "", placeholderTextColor: theme.colors.placeholder, keyboardType: "phone-pad", textContentType: "telephoneNumber", value: phone, onChangeText: onChangePhone, editable: !disabled, maxLength: 15, testID: "chat-registration-phone" })
48
+ }], placeholder: "Phone number", placeholderTextColor: (_b = theme.colors.placeholder) != null ? _b : theme.colors.textSecondary, keyboardType: "phone-pad", textContentType: "telephoneNumber", autoComplete: "tel", value: phone, onChangeText: (text) => onChangePhone(sanitizePhoneInput(text)), onFocus: () => setFocused(true), onBlur: () => setFocused(false), editable: !disabled, maxLength: 15, autoFocus: true, testID: "chat-registration-phone" })
49
+ ] });
50
+ }
51
+ function StepIcon({
52
+ name,
53
+ color
54
+ }) {
55
+ return /* @__PURE__ */ jsx(View, { style: [styles.stepIcon, {
56
+ backgroundColor: `${color}1A`
57
+ }], children: /* @__PURE__ */ jsx(Ionicons, { name, size: 30, color }) });
58
+ }
59
+ const OTP_LENGTH = 6;
60
+ const RESEND_COOLDOWN_SECONDS = 30;
61
+ function OtpCodeInput({
62
+ value,
63
+ onChange,
64
+ disabled,
65
+ hasError,
66
+ theme
67
+ }) {
68
+ const inputRef = React__default.useRef(null);
69
+ const [focused, setFocused] = React__default.useState(false);
70
+ const digits = value.replace(/\D/g, "").slice(0, OTP_LENGTH);
71
+ const accent = theme.colors.primary;
72
+ return /* @__PURE__ */ jsxs(View, { style: styles.otpRow, children: [
73
+ Array.from({
74
+ length: OTP_LENGTH
75
+ }, (_, i) => {
76
+ var _a;
77
+ const active = focused && !disabled && i === Math.min(digits.length, OTP_LENGTH - 1);
78
+ const filled = i < digits.length;
79
+ const borderColor = hasError ? theme.colors.error : active ? accent : filled ? theme.colors.text : theme.colors.border;
80
+ return /* @__PURE__ */ jsx(View, { style: [styles.otpCell, {
81
+ borderColor,
82
+ borderWidth: active || hasError ? 2 : 1,
83
+ backgroundColor: (_a = theme.colors.card) != null ? _a : "#fff"
84
+ }], children: filled ? /* @__PURE__ */ jsx(Text, { style: [styles.otpDigit, {
85
+ color: theme.colors.text
86
+ }], children: digits[i] }) : active ? /* @__PURE__ */ jsx(View, { style: [styles.otpCaret, {
87
+ backgroundColor: accent
88
+ }] }) : null }, i);
89
+ }),
90
+ /* @__PURE__ */ jsx(TextInput, { ref: inputRef, value: digits, onChangeText: (text) => onChange(text.replace(/\D/g, "").slice(0, OTP_LENGTH)), onFocus: () => setFocused(true), onBlur: () => setFocused(false), editable: !disabled, keyboardType: "number-pad", textContentType: "oneTimeCode", autoComplete: Platform.OS === "android" ? "sms-otp" : "one-time-code", autoFocus: true, maxLength: OTP_LENGTH, caretHidden: true, style: styles.otpHiddenInput, accessibilityLabel: "Verification code", testID: "chat-registration-otp" })
115
91
  ] });
116
92
  }
117
93
  function RegistrationScreen({
118
94
  onRegistrationComplete,
119
95
  theme,
120
- testID
96
+ testID,
97
+ onClose
121
98
  }) {
122
- var _a;
99
+ var _a, _b, _c;
123
100
  const phoneVerification = usePhoneVerification("US");
124
101
  const selectedCountry = COUNTRIES.find((c) => c.code === phoneVerification.countryCode) || COUNTRIES[0];
125
102
  const [countryModalOpen, setCountryModalOpen] = React__default.useState(false);
103
+ const [countryQuery, setCountryQuery] = React__default.useState("");
104
+ const visibleCountries = React__default.useMemo(() => filterCountries(COUNTRIES, countryQuery), [countryQuery]);
105
+ const closeCountryModal = React__default.useCallback(() => {
106
+ setCountryModalOpen(false);
107
+ setCountryQuery("");
108
+ }, []);
126
109
  const accent = theme.colors.primary;
127
110
  const otpDigits = phoneVerification.otp.replace(/\D/g, "");
128
111
  const testOtpEnabled = isChatTestOtpEnabled();
@@ -141,17 +124,50 @@ function RegistrationScreen({
141
124
  const handleBack = React__default.useCallback(() => {
142
125
  if (phoneVerification.stage === "otp") {
143
126
  phoneVerification.resetToInput();
127
+ return;
144
128
  }
145
- }, [phoneVerification]);
129
+ onClose == null ? void 0 : onClose();
130
+ }, [phoneVerification, onClose]);
131
+ const [resendIn, setResendIn] = React__default.useState(0);
132
+ React__default.useEffect(() => {
133
+ if (resendIn <= 0) return void 0;
134
+ const timer = setTimeout(() => setResendIn((s) => s - 1), 1e3);
135
+ return () => clearTimeout(timer);
136
+ }, [resendIn]);
146
137
  const handleSendOtp = React__default.useCallback(async () => {
147
- await phoneVerification.sendOtp();
138
+ if (await phoneVerification.sendOtp()) setResendIn(RESEND_COOLDOWN_SECONDS);
148
139
  }, [phoneVerification]);
149
140
  const handleVerifyOtp = React__default.useCallback(async () => {
150
141
  await phoneVerification.verifyOtp();
151
142
  }, [phoneVerification]);
152
143
  const handleResend = React__default.useCallback(async () => {
153
- await phoneVerification.sendOtp();
144
+ if (await phoneVerification.sendOtp()) setResendIn(RESEND_COOLDOWN_SECONDS);
154
145
  }, [phoneVerification]);
146
+ const autoVerifiedFor = React__default.useRef("");
147
+ React__default.useEffect(() => {
148
+ if (phoneVerification.stage !== "otp" || usingTestOtp || phoneVerification.loading) return;
149
+ if (otpDigits.length !== OTP_LENGTH || autoVerifiedFor.current === otpDigits) return;
150
+ autoVerifiedFor.current = otpDigits;
151
+ void phoneVerification.verifyOtp();
152
+ }, [otpDigits, phoneVerification, usingTestOtp]);
153
+ const renderCountryRow = (country) => {
154
+ const selected = phoneVerification.countryCode === country.code;
155
+ return /* @__PURE__ */ jsxs(TouchableOpacity, { onPress: () => {
156
+ phoneVerification.setCountryCode(country.code);
157
+ closeCountryModal();
158
+ }, style: styles.countryListItem, accessibilityRole: "button", accessibilityState: {
159
+ selected
160
+ }, accessibilityLabel: `${country.name} ${country.callingCode}`, children: [
161
+ /* @__PURE__ */ jsx(Text, { style: styles.countryFlag, children: countryFlag(country.code) }),
162
+ /* @__PURE__ */ jsx(Text, { style: [styles.countryListText, {
163
+ color: theme.colors.text
164
+ }, selected && styles.countrySelected], numberOfLines: 1, children: country.name }),
165
+ /* @__PURE__ */ jsx(Text, { style: [styles.countryDial, {
166
+ color: theme.colors.textSecondary
167
+ }], children: country.callingCode }),
168
+ /* @__PURE__ */ jsx(View, { style: styles.countryCheck, children: selected ? /* @__PURE__ */ jsx(Ionicons, { name: "checkmark-circle", size: 22, color: accent }) : null })
169
+ ] });
170
+ };
155
171
  return /* @__PURE__ */ jsxs(SafeAreaView, { style: [styles.container, {
156
172
  backgroundColor: theme.colors.background
157
173
  }], edges: ["top", "left", "right"], testID, children: [
@@ -159,12 +175,12 @@ function RegistrationScreen({
159
175
  flexDirection: "row",
160
176
  alignItems: "center"
161
177
  }], children: [
162
- phoneVerification.stage === "otp" ? /* @__PURE__ */ jsx(TouchableOpacity, { onPress: handleBack, hitSlop: {
178
+ phoneVerification.stage === "otp" || onClose ? /* @__PURE__ */ jsx(TouchableOpacity, { onPress: handleBack, hitSlop: {
163
179
  top: 10,
164
180
  bottom: 10,
165
181
  left: 10,
166
182
  right: 10
167
- }, children: /* @__PURE__ */ jsx(Ionicons, { name: "chevron-back", size: 28, color: theme.colors.text }) }) : /* @__PURE__ */ jsx(View, { style: {
183
+ }, accessibilityRole: "button", accessibilityLabel: phoneVerification.stage === "otp" ? "Change phone number" : "Back", testID: "chat-registration-back", children: /* @__PURE__ */ jsx(Ionicons, { name: "chevron-back", size: 28, color: theme.colors.text }) }) : /* @__PURE__ */ jsx(View, { style: {
168
184
  width: 28
169
185
  } }),
170
186
  /* @__PURE__ */ jsx(Text, { style: [styles.title, {
@@ -177,90 +193,146 @@ function RegistrationScreen({
177
193
  } })
178
194
  ] }),
179
195
  /* @__PURE__ */ jsx(ScrollView, { contentContainerStyle: styles.content, showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "handled", children: phoneVerification.stage === "input" ? /* @__PURE__ */ jsxs(Fragment, { children: [
196
+ /* @__PURE__ */ jsx(StepIcon, { name: "chatbubbles", color: accent }),
180
197
  /* @__PURE__ */ jsx(Text, { style: [styles.subtitle, {
181
198
  color: theme.colors.text
182
- }], children: "Register to Chat" }),
199
+ }], children: "Enter your phone number" }),
183
200
  /* @__PURE__ */ jsx(Text, { style: [styles.description, {
184
201
  color: theme.colors.textSecondary
185
- }], children: "Enter your mobile number to get started. You'll receive an OTP to verify." }),
202
+ }], children: "Yantra Chat will send you a text with a 6-digit code to verify your number." }),
186
203
  /* @__PURE__ */ jsxs(View, { style: styles.form, children: [
187
- /* @__PURE__ */ jsx(PhoneRow, { countryCode: phoneVerification.countryCode, callingCode: selectedCountry.callingCode, phone: phoneVerification.inputPhone, onCountryPress: () => setCountryModalOpen(true), onChangePhone: phoneVerification.setInputPhone, disabled: phoneVerification.loading, theme }),
204
+ /* @__PURE__ */ jsx(PhoneRow, { countryCode: phoneVerification.countryCode, callingCode: selectedCountry.callingCode, phone: phoneVerification.inputPhone, onCountryPress: () => setCountryModalOpen(true), onChangePhone: (value) => {
205
+ if (phoneVerification.error) phoneVerification.clearError();
206
+ phoneVerification.setInputPhone(value);
207
+ }, disabled: phoneVerification.loading, theme }),
188
208
  phoneVerification.error ? /* @__PURE__ */ jsxs(View, { style: [styles.errorBox, {
189
- backgroundColor: theme.colors.error + "10"
209
+ backgroundColor: `${theme.colors.error}10`
190
210
  }], children: [
191
211
  /* @__PURE__ */ jsx(Ionicons, { name: "alert-circle", size: 16, color: theme.colors.error }),
192
212
  /* @__PURE__ */ jsx(Text, { style: [styles.errorText, {
193
213
  color: theme.colors.error
194
214
  }], children: phoneVerification.error })
195
215
  ] }) : null,
196
- testOtpEnabled ? /* @__PURE__ */ jsx(TouchableOpacity, { onPress: phoneVerification.continueWithTestOtp, children: /* @__PURE__ */ jsx(Text, { style: [styles.linkText, {
197
- color: accent
198
- }], children: "Continue with test OTP" }) }) : null,
199
216
  /* @__PURE__ */ jsx(TouchableOpacity, { onPress: handleSendOtp, disabled: phoneVerification.loading || !phoneVerification.inputPhone.trim(), style: [styles.button, {
200
- backgroundColor: phoneVerification.inputPhone.trim() ? accent : theme.colors.border
201
- }], children: phoneVerification.loading ? /* @__PURE__ */ jsx(ActivityIndicator, { color: "#fff", size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.buttonText, children: "Send OTP" }) })
217
+ backgroundColor: accent,
218
+ opacity: phoneVerification.inputPhone.trim() || phoneVerification.loading ? 1 : 0.4
219
+ }], children: phoneVerification.loading ? /* @__PURE__ */ jsx(ActivityIndicator, { color: "#fff", size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.buttonText, children: "Send code" }) }),
220
+ testOtpEnabled ? /* @__PURE__ */ jsxs(TouchableOpacity, { onPress: phoneVerification.continueWithTestOtp, style: [styles.testOtpChip, {
221
+ borderColor: theme.colors.border
222
+ }], children: [
223
+ /* @__PURE__ */ jsx(Ionicons, { name: "flask-outline", size: 14, color: theme.colors.textSecondary }),
224
+ /* @__PURE__ */ jsx(Text, { style: [styles.testOtpText, {
225
+ color: theme.colors.textSecondary
226
+ }], children: "Continue with test OTP" })
227
+ ] }) : null
202
228
  ] })
203
229
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
230
+ /* @__PURE__ */ jsx(StepIcon, { name: "shield-checkmark", color: accent }),
204
231
  /* @__PURE__ */ jsx(Text, { style: [styles.subtitle, {
205
232
  color: theme.colors.text
206
233
  }], children: "Verify your number" }),
207
- /* @__PURE__ */ jsx(Text, { style: [styles.description, {
234
+ usingTestOtp ? /* @__PURE__ */ jsxs(Text, { style: [styles.description, {
208
235
  color: theme.colors.textSecondary
209
- }], children: usingTestOtp ? `Test mode: use code ${CHAT_REGISTRATION_TEST_OTP} and tap Continue.` : `Enter the 6-digit code sent to ${selectedCountry.callingCode} ${phoneVerification.inputPhone}` }),
236
+ }], children: [
237
+ "Test mode: use code ",
238
+ CHAT_REGISTRATION_TEST_OTP,
239
+ " and tap Continue."
240
+ ] }) : /* @__PURE__ */ jsxs(Text, { style: [styles.description, {
241
+ color: theme.colors.textSecondary
242
+ }], children: [
243
+ "Enter the 6-digit code we sent to",
244
+ "\n",
245
+ /* @__PURE__ */ jsxs(Text, { style: [styles.phoneStrong, {
246
+ color: theme.colors.text
247
+ }], children: [
248
+ selectedCountry.callingCode,
249
+ " ",
250
+ phoneVerification.inputPhone
251
+ ] }),
252
+ " ",
253
+ /* @__PURE__ */ jsx(Text, { style: [styles.inlineLink, {
254
+ color: accent
255
+ }], onPress: phoneVerification.loading ? void 0 : phoneVerification.resetToInput, accessibilityRole: "link", children: "Wrong number?" })
256
+ ] }),
210
257
  /* @__PURE__ */ jsxs(View, { style: styles.form, children: [
211
- /* @__PURE__ */ jsx(View, { style: [styles.otpInputContainer, {
212
- flexDirection: "row",
213
- alignItems: "center",
214
- borderColor: theme.colors.border,
215
- backgroundColor: (_a = theme.colors.card) != null ? _a : "#fff"
216
- }], children: /* @__PURE__ */ jsx(TextInput, { style: [styles.otpInput, {
217
- color: theme.colors.text,
218
- flex: 1
219
- }], placeholder: "", keyboardType: "number-pad", value: phoneVerification.otp, onChangeText: phoneVerification.setOtp, editable: !phoneVerification.loading, maxLength: 6, testID: "chat-registration-otp" }) }),
258
+ /* @__PURE__ */ jsx(OtpCodeInput, { value: phoneVerification.otp, onChange: phoneVerification.setOtp, disabled: phoneVerification.loading, hasError: Boolean(phoneVerification.error), theme }),
220
259
  phoneVerification.error ? /* @__PURE__ */ jsxs(View, { style: [styles.errorBox, {
221
- backgroundColor: theme.colors.error + "10"
260
+ backgroundColor: `${theme.colors.error}10`
222
261
  }], children: [
223
262
  /* @__PURE__ */ jsx(Ionicons, { name: "alert-circle", size: 16, color: theme.colors.error }),
224
263
  /* @__PURE__ */ jsx(Text, { style: [styles.errorText, {
225
264
  color: theme.colors.error
226
265
  }], children: phoneVerification.error })
227
266
  ] }) : null,
228
- /* @__PURE__ */ jsx(TouchableOpacity, { onPress: handleVerifyOtp, disabled: phoneVerification.loading || otpDigits.length < 6, style: [styles.button, {
229
- backgroundColor: otpDigits.length >= 6 ? accent : theme.colors.border
230
- }], children: phoneVerification.loading ? /* @__PURE__ */ jsx(ActivityIndicator, { color: "#fff", size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.buttonText, children: usingTestOtp ? "Continue" : "Verify & Register" }) }),
231
- !usingTestOtp ? /* @__PURE__ */ jsx(TouchableOpacity, { onPress: handleResend, disabled: phoneVerification.loading, children: /* @__PURE__ */ jsx(Text, { style: [styles.linkText, {
232
- color: accent
233
- }], children: "Didn't get the code? Resend" }) }) : null
267
+ /* @__PURE__ */ jsx(TouchableOpacity, { onPress: handleVerifyOtp, disabled: phoneVerification.loading || otpDigits.length < OTP_LENGTH, style: [styles.button, {
268
+ backgroundColor: accent,
269
+ opacity: otpDigits.length >= OTP_LENGTH || phoneVerification.loading ? 1 : 0.4
270
+ }], children: phoneVerification.loading ? /* @__PURE__ */ jsx(ActivityIndicator, { color: "#fff", size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.buttonText, children: usingTestOtp ? "Continue" : "Verify" }) }),
271
+ !usingTestOtp ? /* @__PURE__ */ jsxs(View, { style: styles.resendRow, children: [
272
+ /* @__PURE__ */ jsx(Text, { style: [styles.resendHint, {
273
+ color: theme.colors.textSecondary
274
+ }], children: "Didn't get the code?" }),
275
+ resendIn > 0 ? /* @__PURE__ */ jsxs(Text, { style: [styles.resendHint, {
276
+ color: theme.colors.textSecondary
277
+ }], children: [
278
+ "Resend in 0:",
279
+ String(resendIn).padStart(2, "0")
280
+ ] }) : /* @__PURE__ */ jsx(TouchableOpacity, { onPress: handleResend, disabled: phoneVerification.loading, hitSlop: {
281
+ top: 8,
282
+ bottom: 8,
283
+ left: 8,
284
+ right: 8
285
+ }, children: /* @__PURE__ */ jsx(Text, { style: [styles.inlineLink, {
286
+ color: accent
287
+ }], children: "Resend code" }) })
288
+ ] }) : null
234
289
  ] })
235
290
  ] }) }),
236
- /* @__PURE__ */ jsx(Modal, { visible: countryModalOpen, animationType: "slide", presentationStyle: "pageSheet", children: /* @__PURE__ */ jsxs(SafeAreaView, { style: [styles.modalFill, {
291
+ /* @__PURE__ */ jsx(Modal, { visible: countryModalOpen, animationType: "slide", presentationStyle: "pageSheet", onRequestClose: closeCountryModal, children: /* @__PURE__ */ jsxs(SafeAreaView, { style: [styles.modalFill, {
237
292
  backgroundColor: theme.colors.background
238
293
  }], children: [
239
- /* @__PURE__ */ jsxs(View, { style: [styles.modalHeader, {
240
- flexDirection: "row",
241
- alignItems: "center"
242
- }], children: [
294
+ /* @__PURE__ */ jsx(View, { style: styles.modalHandle, children: /* @__PURE__ */ jsx(View, { style: [styles.modalHandleBar, {
295
+ backgroundColor: theme.colors.border
296
+ }] }) }),
297
+ /* @__PURE__ */ jsxs(View, { style: styles.modalHeader, children: [
298
+ /* @__PURE__ */ jsx(TouchableOpacity, { onPress: closeCountryModal, accessibilityRole: "button", accessibilityLabel: "Close", hitSlop: {
299
+ top: 10,
300
+ bottom: 10,
301
+ left: 10,
302
+ right: 10
303
+ }, style: [styles.modalClose, {
304
+ backgroundColor: `${theme.colors.text}0D`
305
+ }], children: /* @__PURE__ */ jsx(Ionicons, { name: "close", size: 20, color: theme.colors.text }) }),
243
306
  /* @__PURE__ */ jsx(Text, { style: [styles.modalTitle, {
244
307
  color: theme.colors.text
245
- }], children: "Country code" }),
246
- /* @__PURE__ */ jsx(TouchableOpacity, { onPress: () => setCountryModalOpen(false), children: /* @__PURE__ */ jsx(Ionicons, { name: "close", size: 26, color: theme.colors.text }) })
308
+ }], children: "Choose a country" }),
309
+ /* @__PURE__ */ jsx(View, { style: styles.modalClose })
247
310
  ] }),
248
- /* @__PURE__ */ jsx(ScrollView, { children: COUNTRIES.map((country) => /* @__PURE__ */ jsxs(TouchableOpacity, { onPress: () => {
249
- phoneVerification.setCountryCode(country.code);
250
- setCountryModalOpen(false);
251
- }, style: [styles.countryListItem, phoneVerification.countryCode === country.code && {
252
- backgroundColor: accent + "18"
311
+ /* @__PURE__ */ jsxs(View, { style: [styles.countrySearch, {
312
+ backgroundColor: `${theme.colors.text}0D`
253
313
  }], children: [
254
- /* @__PURE__ */ jsxs(Text, { style: [styles.countryListText, {
314
+ /* @__PURE__ */ jsx(Ionicons, { name: "search", size: 18, color: (_a = theme.colors.textSecondary) != null ? _a : theme.colors.text }),
315
+ /* @__PURE__ */ jsx(TextInput, { value: countryQuery, onChangeText: setCountryQuery, placeholder: "Search countries", placeholderTextColor: (_b = theme.colors.textSecondary) != null ? _b : "#888", autoCorrect: false, autoCapitalize: "none", clearButtonMode: "while-editing", returnKeyType: "search", style: [styles.countrySearchInput, {
255
316
  color: theme.colors.text
256
- }], children: [
257
- country.name,
258
- " (",
259
- country.callingCode,
260
- ")"
261
- ] }),
262
- phoneVerification.countryCode === country.code ? /* @__PURE__ */ jsx(Ionicons, { name: "checkmark", size: 20, color: accent }) : null
263
- ] }, country.code)) })
317
+ }], testID: "country-search" })
318
+ ] }),
319
+ /* @__PURE__ */ jsx(FlatList, { data: visibleCountries, keyExtractor: (country) => country.code, keyboardShouldPersistTaps: "handled", keyboardDismissMode: "on-drag", initialNumToRender: 24, ListHeaderComponent: countryQuery.trim() ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
320
+ /* @__PURE__ */ jsx(Text, { style: [styles.countrySection, {
321
+ color: theme.colors.textSecondary
322
+ }], children: "SELECTED" }),
323
+ renderCountryRow(selectedCountry),
324
+ /* @__PURE__ */ jsx(Text, { style: [styles.countrySection, {
325
+ color: theme.colors.textSecondary
326
+ }], children: "ALL COUNTRIES" })
327
+ ] }), ListEmptyComponent: /* @__PURE__ */ jsxs(Text, { style: [styles.countryEmpty, {
328
+ color: (_c = theme.colors.textSecondary) != null ? _c : theme.colors.text
329
+ }], children: [
330
+ 'No country matches "',
331
+ countryQuery.trim(),
332
+ '"'
333
+ ] }), renderItem: ({
334
+ item: country
335
+ }) => renderCountryRow(country) })
264
336
  ] }) })
265
337
  ] });
266
338
  }
@@ -282,57 +354,121 @@ const styles = StyleSheet.create({
282
354
  paddingBottom: 40
283
355
  },
284
356
  subtitle: {
285
- fontSize: 22,
357
+ fontSize: 26,
286
358
  fontWeight: "700",
359
+ letterSpacing: -0.4,
287
360
  marginBottom: 8
288
361
  },
289
362
  description: {
290
- fontSize: 14,
291
- marginBottom: 24,
292
- lineHeight: 20
363
+ fontSize: 15,
364
+ marginBottom: 28,
365
+ lineHeight: 22
366
+ },
367
+ stepIcon: {
368
+ width: 60,
369
+ height: 60,
370
+ borderRadius: 18,
371
+ alignItems: "center",
372
+ justifyContent: "center",
373
+ marginBottom: 20
293
374
  },
294
375
  form: {
295
376
  gap: 14
296
377
  },
297
378
  phoneRow: {
298
- borderWidth: 1,
299
- borderRadius: 10,
300
- minHeight: 48,
301
- overflow: "hidden"
379
+ flexDirection: "row",
380
+ alignItems: "center",
381
+ borderRadius: 14,
382
+ minHeight: 56,
383
+ padding: 5,
384
+ gap: 6
302
385
  },
303
386
  countryChip: {
304
- paddingHorizontal: 12,
305
- paddingVertical: 12
387
+ flexDirection: "row",
388
+ alignItems: "center",
389
+ gap: 6,
390
+ borderRadius: 10,
391
+ paddingHorizontal: 10,
392
+ alignSelf: "stretch"
393
+ },
394
+ countryChipFlag: {
395
+ fontSize: 22
306
396
  },
307
397
  callingCode: {
308
398
  fontSize: 16,
309
- fontWeight: "600",
310
- marginRight: 4
311
- },
312
- phoneDivider: {
313
- width: StyleSheet.hairlineWidth,
314
- alignSelf: "stretch"
399
+ fontWeight: "600"
315
400
  },
316
401
  phoneInput: {
317
402
  flex: 1,
318
- paddingHorizontal: 12,
319
- paddingVertical: Platform.OS === "ios" ? 12 : 10,
320
- fontSize: 16
403
+ paddingHorizontal: 8,
404
+ paddingVertical: Platform.OS === "ios" ? 12 : 8,
405
+ fontSize: 18,
406
+ letterSpacing: 0.3
321
407
  },
322
- otpInputContainer: {
408
+ testOtpChip: {
409
+ flexDirection: "row",
410
+ alignItems: "center",
411
+ alignSelf: "center",
412
+ gap: 6,
323
413
  borderWidth: 1,
324
- borderRadius: 10,
325
- paddingHorizontal: 16
414
+ borderStyle: "dashed",
415
+ borderRadius: 999,
416
+ paddingHorizontal: 14,
417
+ paddingVertical: 8,
418
+ marginTop: 8
326
419
  },
327
- otpInput: {
328
- paddingVertical: 14,
329
- fontSize: 22,
330
- fontWeight: "600",
331
- letterSpacing: 6,
332
- textAlign: "center"
420
+ testOtpText: {
421
+ fontSize: 13,
422
+ fontWeight: "500"
423
+ },
424
+ otpRow: {
425
+ flexDirection: "row",
426
+ justifyContent: "space-between",
427
+ gap: 8
428
+ },
429
+ otpCell: {
430
+ flex: 1,
431
+ maxWidth: 52,
432
+ aspectRatio: 0.85,
433
+ borderRadius: 12,
434
+ alignItems: "center",
435
+ justifyContent: "center"
436
+ },
437
+ otpDigit: {
438
+ fontSize: 24,
439
+ fontWeight: "600"
440
+ },
441
+ otpCaret: {
442
+ width: 2,
443
+ height: 26,
444
+ borderRadius: 1
445
+ },
446
+ // Covers the boxes so a tap anywhere focuses it; near-zero opacity keeps iOS code autofill working.
447
+ otpHiddenInput: __spreadProps(__spreadValues({}, StyleSheet.absoluteFillObject), {
448
+ opacity: 0.011,
449
+ color: "transparent",
450
+ fontSize: 1
451
+ }),
452
+ phoneStrong: {
453
+ fontWeight: "600"
454
+ },
455
+ inlineLink: {
456
+ fontSize: 14,
457
+ fontWeight: "600"
458
+ },
459
+ resendRow: {
460
+ flexDirection: "row",
461
+ justifyContent: "center",
462
+ alignItems: "center",
463
+ gap: 6,
464
+ marginTop: 4
465
+ },
466
+ resendHint: {
467
+ fontSize: 14
333
468
  },
334
469
  button: {
335
- borderRadius: 10,
470
+ borderRadius: 14,
471
+ minHeight: 54,
336
472
  paddingVertical: 14,
337
473
  alignItems: "center",
338
474
  justifyContent: "center",
@@ -340,13 +476,13 @@ const styles = StyleSheet.create({
340
476
  },
341
477
  buttonText: {
342
478
  color: "#fff",
343
- fontSize: 16,
479
+ fontSize: 17,
344
480
  fontWeight: "600"
345
481
  },
346
482
  errorBox: {
347
483
  flexDirection: "row",
348
484
  alignItems: "center",
349
- borderRadius: 8,
485
+ borderRadius: 12,
350
486
  paddingHorizontal: 12,
351
487
  paddingVertical: 10,
352
488
  gap: 8
@@ -355,33 +491,90 @@ const styles = StyleSheet.create({
355
491
  fontSize: 13,
356
492
  flex: 1
357
493
  },
358
- linkText: {
359
- fontSize: 14,
360
- textAlign: "center",
361
- fontWeight: "500"
362
- },
363
494
  modalFill: {
364
495
  flex: 1
365
496
  },
497
+ modalHandle: {
498
+ alignItems: "center",
499
+ paddingTop: 8
500
+ },
501
+ modalHandleBar: {
502
+ width: 36,
503
+ height: 5,
504
+ borderRadius: 3
505
+ },
366
506
  modalHeader: {
507
+ flexDirection: "row",
508
+ alignItems: "center",
367
509
  justifyContent: "space-between",
368
510
  paddingHorizontal: 16,
369
511
  paddingVertical: 12
370
512
  },
513
+ modalClose: {
514
+ width: 32,
515
+ height: 32,
516
+ borderRadius: 16,
517
+ alignItems: "center",
518
+ justifyContent: "center"
519
+ },
371
520
  modalTitle: {
372
- fontSize: 18,
521
+ fontSize: 17,
373
522
  fontWeight: "700"
374
523
  },
524
+ countrySearch: {
525
+ flexDirection: "row",
526
+ alignItems: "center",
527
+ gap: 8,
528
+ marginHorizontal: 16,
529
+ marginBottom: 4,
530
+ paddingHorizontal: 12,
531
+ borderRadius: 12,
532
+ minHeight: 42
533
+ },
534
+ countrySearchInput: {
535
+ flex: 1,
536
+ fontSize: 16,
537
+ paddingVertical: Platform.OS === "ios" ? 10 : 6
538
+ },
539
+ countryEmpty: {
540
+ textAlign: "center",
541
+ padding: 24,
542
+ fontSize: 14
543
+ },
544
+ countrySection: {
545
+ fontSize: 12,
546
+ fontWeight: "600",
547
+ letterSpacing: 0.6,
548
+ paddingHorizontal: 20,
549
+ paddingTop: 18,
550
+ paddingBottom: 6
551
+ },
375
552
  countryListItem: {
376
553
  flexDirection: "row",
377
554
  alignItems: "center",
378
- justifyContent: "space-between",
379
- paddingHorizontal: 16,
380
- paddingVertical: 14,
381
- borderBottomWidth: StyleSheet.hairlineWidth,
382
- borderBottomColor: "rgba(0,0,0,0.06)"
555
+ gap: 14,
556
+ paddingHorizontal: 20,
557
+ minHeight: 52
558
+ },
559
+ countryFlag: {
560
+ fontSize: 26,
561
+ width: 32,
562
+ textAlign: "center"
383
563
  },
384
564
  countryListText: {
565
+ flex: 1,
385
566
  fontSize: 16
567
+ },
568
+ countrySelected: {
569
+ fontWeight: "600"
570
+ },
571
+ countryDial: {
572
+ fontSize: 15,
573
+ minWidth: 48,
574
+ textAlign: "right"
575
+ },
576
+ countryCheck: {
577
+ width: 22,
578
+ alignItems: "center"
386
579
  }
387
- });export{RegistrationScreen,allowedDialCodes,pickerCountries};//# sourceMappingURL=RegistrationScreen.js.map
580
+ });export{RegistrationScreen};//# sourceMappingURL=RegistrationScreen.js.map