Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export default {
name: 'Aashray',
scheme: 'aashray',
slug: 'aashray',
version: '1.1.46',
version: '1.1.48',
orientation: 'portrait',
icon: './src/assets/images/icon.png',
userInterfaceStyle: 'automatic',
Expand Down
3,865 changes: 2,768 additions & 1,097 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@shopify/flash-list": "2.0.2",
"@tanstack/react-query": "^5.54.1",
"axios": "^1.6.8",
"expo": "^54.0.9",
"expo": "^54.0.31",
"expo-application": "~7.0.7",
"expo-blur": "~15.0.7",
"expo-build-properties": "~1.0.9",
Expand Down
263 changes: 102 additions & 161 deletions src/app/(auth)/sign-in.tsx
Original file line number Diff line number Diff line change
@@ -1,92 +1,75 @@
import React, { useState } from 'react';
import { View, Text, Image, Alert, TouchableOpacity, Modal } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller';
import { Image, Keyboard, Modal, Pressable, Text, View } from 'react-native';
import Reanimated, { useAnimatedStyle } from 'react-native-reanimated';
import { useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { images } from '@/src/constants';
import { useAuthStore } from '@/src/stores';
import { useNotification } from '@/src/context/NotificationContext';
import FormField from '@/src/components/FormField';
import CustomButton from '@/src/components/CustomButton';
import handleAPICall from '@/src/utils/HandleApiCall';
import CustomAlert from '@/src/components/CustomAlert';
import FormField from '@/src/components/FormField';
import CustomButton from '@/src/components/CustomButton';

const PasswordResetModal = ({ visible, onClose, email }: any) => {
return (
<Modal
animationType="fade"
transparent={true}
visible={visible}
onRequestClose={onClose}
statusBarTranslucent={true}>
<View className="flex-1 items-center justify-center bg-black/50 px-6">
<View className="w-full max-w-[400px] items-center rounded-2xl bg-white p-8 shadow-xl">
<View className="mb-6 h-16 w-16 items-center justify-center rounded-full bg-secondary-50">
<Image source={images.logo} className="h-10 w-10" resizeMode="contain" />
</View>

<Text className="mb-3 font-psemibold text-2xl text-gray-900">Check Your Email</Text>

<Text className="mb-2 text-center font-pregular text-sm text-gray-600">
We've sent a temporary password to:
</Text>

<Text className="mb-5 text-center font-pmedium text-base text-secondary-100">
{email}
</Text>

<Text className="mb-8 text-center font-pregular text-sm text-gray-600">
Please use it to sign in and then change your password from your profile.
</Text>

<CustomButton containerStyles="w-full h-12" text="Got It" handlePress={onClose} />
const PasswordResetModal = ({ visible, onClose, email }: any) => (
<Modal
animationType="fade"
transparent
visible={visible}
onRequestClose={onClose}
statusBarTranslucent>
<View className="flex-1 items-center justify-center bg-black/45 px-7">
<View className="w-full max-w-[400px] items-center rounded-[28px] bg-white p-8">
<View className="mb-5 h-16 w-16 items-center justify-center rounded-full bg-secondary-50">
<Image source={images.logo} className="h-10 w-10" resizeMode="contain" />
</View>

<Text className="mb-3 font-dmserif text-[26px] text-black">Check Your Email</Text>
<Text className="font-pregular text-sm text-gray-600">
We've sent a temporary password to:
</Text>
<Text className="mb-4 mt-1 font-pmedium text-base text-secondary">{email}</Text>
<Text className="mb-7 text-center font-pregular text-sm leading-5 text-gray-500">
Please use it to sign in and then change your password from your profile.
</Text>

<CustomButton text="Got It" handlePress={onClose} variant="pill" containerStyles="w-full" />
</View>
</Modal>
);
};
</View>
</Modal>
);

const SignIn = () => {
const [form, setForm] = useState({
phone: '',
password: '',
});
const insets = useSafeAreaInsets();

const [form, setForm] = useState({ phone: '', password: '' });
const [isSubmitting, setIsSubmitting] = useState(false);
const [resetEmail, setResetEmail] = useState('');
const [modalVisible, setModalVisible] = useState(false);

const setUser = useAuthStore((state) => state.setUser);
const setUser = useAuthStore((state: any) => state.setUser);
const { expoPushToken } = useNotification();

const submit = async () => {
setIsSubmitting(true);
const isReady = form.phone.length === 10 && !!form.password;

if (!form.phone || form.phone.length < 10 || !form.password) {
CustomAlert.alert('Error', 'Please fill the fields correctly');
setIsSubmitting(false);
return;
}
// Tracks OS keyboard spring curve exactly — runs on UI thread
const { height: keyboardHeight } = useReanimatedKeyboardAnimation();

const onSuccess = async (data: any) => {
const updatedUser = data.data;
setUser(updatedUser);
};

const onFinally = () => {
setIsSubmitting(false);
};
// Translates the block upward by the keyboard height, keeping it anchored to the bottom
const blockStyle = useAnimatedStyle(() => ({
transform: [{ translateY: keyboardHeight.value }],
}));

const submit = async () => {
if (!isReady) return;
setIsSubmitting(true);
await handleAPICall(
'POST',
'/client/verifyAndLogin',
null,
{
mobno: form.phone,
password: form.password,
token: expoPushToken,
},
onSuccess,
onFinally
{ mobno: form.phone, password: form.password, token: expoPushToken },
async (data: any) => setUser(data.data),
() => setIsSubmitting(false)
);
};

Expand All @@ -103,118 +86,76 @@ const SignIn = () => {
style: 'default',
onPress: async () => {
setIsSubmitting(true);
const onSuccess = async (data: any) => {
setResetEmail(data?.data.email);
setModalVisible(true);
};

const onFinally = () => {
setIsSubmitting(false);
};

await handleAPICall(
'POST',
'/client/forgotPassword',
null,
{
mobno: form.phone,
{ mobno: form.phone },
async (data: any) => {
setResetEmail(data?.data.email);
setModalVisible(true);
},
onSuccess,
onFinally
() => setIsSubmitting(false)
);
},
},
]);
};

return (
<SafeAreaView className="h-full bg-gray-100">
<KeyboardAwareScrollView
contentContainerStyle={{
flexGrow: 1,
paddingHorizontal: 24,
paddingTop: 32,
paddingBottom: 32,
}}
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}>
<View className="items-center">
<Image source={images.vvTra} className="h-[80px] w-[80px]" resizeMode="contain" />
</View>
<Pressable className="flex-1 justify-end bg-white" onPress={Keyboard.dismiss}>
<Reanimated.View
style={[blockStyle, { paddingBottom: insets.bottom + 40 }]}
className="px-6 pt-10">
<Image source={images.vvTra} className="h-[80px] w-[80px]" resizeMode="contain" />

<Text className="mb-2 font-dmserif text-[36px] leading-[44px] text-black">
Jai Sadgurudev{'\n'}Vandan!
</Text>
<Text className="mb-8 mt-1 font-pregular text-base text-gray-400">
Sign in to continue your journey
</Text>

<FormField
text="Phone Number"
value={form.phone}
handleChangeText={(e: any) => setForm({ ...form, phone: e })}
placeholder="10-digit phone number"
keyboardType="number-pad"
maxLength={10}
otherStyles="mb-3"
variant="clean"
/>

<View className="flex-1 justify-center">
<View className="mb-10">
<Text className="mb-2 text-center font-psemibold text-3xl text-gray-900">
Jai Sadgurudev Vandan!
</Text>
<Text className="text-center font-pregular text-base text-gray-600">
Sign in to your account
</Text>
</View>

<View>
<FormField
text="Phone Number"
value={form.phone}
handleChangeText={(e: any) => setForm({ ...form, phone: e })}
otherStyles="mb-5"
inputStyles="font-pmedium text-base text-black"
keyboardType="number-pad"
placeholder="10-digit phone number"
maxLength={10}
useNeomorphic={true}
/>

<FormField
text="Password"
value={form.password}
handleChangeText={(e: any) => setForm({ ...form, password: e })}
placeholder="Enter your password"
otherStyles="mb-3"
inputStyles="font-pmedium text-base text-black"
keyboardType="default"
isPassword={true}
useNeomorphic={true}
/>

<View className="mb-7 flex flex-row items-center justify-end">
<TouchableOpacity onPress={handleForgotPassword} activeOpacity={0.7} className="py-2">
<Text className="font-pmedium text-sm text-secondary-100">Forgot password?</Text>
</TouchableOpacity>
</View>

<CustomButton
text="Sign In"
handlePress={submit}
containerStyles="h-14 mb-8"
isLoading={isSubmitting}
isDisabled={form.phone.length !== 10 || !form.password}
/>

{/* Divider - Closer to button */}
{/* <View className="mb-6 flex flex-row items-center">
<View className="h-[1px] flex-1 bg-gray-200" />
<Text className="mx-4 font-pregular text-sm text-gray-500">or</Text>
<View className="h-[1px] flex-1 bg-gray-200" />
</View> */}

{/* Sign Up CTA */}
{/* <View className="flex flex-row items-center justify-center">
<Text className="font-pregular text-sm text-gray-600">New to SRATRC? </Text>
<TouchableOpacity activeOpacity={0.7}>
<Text className="font-psemibold text-sm text-secondary-100">Create account</Text>
</TouchableOpacity>
</View> */}
</View>
</View>
<FormField
text="Password"
value={form.password}
handleChangeText={(e: any) => setForm({ ...form, password: e })}
placeholder="Enter your password"
isPassword
otherStyles="mb-2"
variant="clean"
/>

<Pressable onPress={handleForgotPassword} className="mb-7 self-end py-1" hitSlop={8}>
<Text className="font-pregular text-sm text-gray-400">Forgot password?</Text>
</Pressable>

<PasswordResetModal
visible={modalVisible}
onClose={() => setModalVisible(false)}
email={resetEmail}
<CustomButton
text="Sign In"
handlePress={submit}
variant="pill"
isLoading={isSubmitting}
isDisabled={!isReady}
/>
</KeyboardAwareScrollView>
</SafeAreaView>
</Reanimated.View>

<PasswordResetModal
visible={modalVisible}
onClose={() => setModalVisible(false)}
email={resetEmail}
/>
</Pressable>
);
};

Expand Down
1 change: 1 addition & 0 deletions src/app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ImageSourcePropType,
ActivityIndicator,
Platform,
TouchableOpacity,
} from 'react-native';
import { useRouter } from 'expo-router';
import { SafeAreaView } from 'react-native-safe-area-context';
Expand Down
4 changes: 4 additions & 0 deletions src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ const RootLayout = () => {
'Poppins-Regular': require('@/src/assets/fonts/Poppins-Regular.ttf'),
'Poppins-SemiBold': require('@/src/assets/fonts/Poppins-SemiBold.ttf'),
'Poppins-Thin': require('@/src/assets/fonts/Poppins-Thin.ttf'),
'DMSerifDisplay-Regular': require('@/src/assets/fonts/DMSerifDisplay-Regular.ttf'),
'DMSans-Regular': require('@/src/assets/fonts/DMSans-Regular.ttf'),
'DMSans-Medium': require('@/src/assets/fonts/DMSans-Medium.ttf'),
'DMSans-Light': require('@/src/assets/fonts/DMSans-Light.ttf'),
});

const [isAuthReady, setIsAuthReady] = useState(false);
Expand Down
Loading