app-expo-cli 1.0.0

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.
Files changed (46) hide show
  1. package/bin/index.js +3 -0
  2. package/bun.lock +82 -0
  3. package/package.json +26 -0
  4. package/src/copy-template.js +156 -0
  5. package/src/create-expo.js +10 -0
  6. package/src/index.js +39 -0
  7. package/src/install-deps.js +22 -0
  8. package/src/utils/logger.js +29 -0
  9. package/tailwind.config.js +69 -0
  10. package/template/src/app/_layout.tsx +61 -0
  11. package/template/src/app/auth/_layout.tsx +41 -0
  12. package/template/src/app/auth/change_pass.tsx +138 -0
  13. package/template/src/app/auth/change_pass_modal.tsx +74 -0
  14. package/template/src/app/auth/forgot.tsx +124 -0
  15. package/template/src/app/auth/index.tsx +274 -0
  16. package/template/src/app/auth/opt_verify.tsx +145 -0
  17. package/template/src/app/auth/register.tsx +334 -0
  18. package/template/src/app/auth/reset_pass.tsx +152 -0
  19. package/template/src/app/common/image.tsx +202 -0
  20. package/template/src/app/common/openurl.tsx +42 -0
  21. package/template/src/app/home/_layout.tsx +29 -0
  22. package/template/src/app/home/drawer/_layout.tsx +27 -0
  23. package/template/src/app/home/tabs/_layout.tsx +75 -0
  24. package/template/src/app/home/tabs/index.tsx +11 -0
  25. package/template/src/app/index.tsx +11 -0
  26. package/template/src/app/modals/confirmation_logout_modal.tsx +78 -0
  27. package/template/src/app/modals/payment_modal.tsx +105 -0
  28. package/template/src/app/modals/success_modal.tsx +72 -0
  29. package/template/src/app/modals/toaster.tsx +31 -0
  30. package/template/src/app/settings/_layout.tsx +19 -0
  31. package/template/src/app/settings/about_us.tsx +61 -0
  32. package/template/src/app/settings/privacy_policy.tsx +61 -0
  33. package/template/src/app/settings/terms_and_conditions.tsx +60 -0
  34. package/template/src/hooks/useCheckLocation.ts +36 -0
  35. package/template/src/hooks/useDocPicker.ts +83 -0
  36. package/template/src/hooks/useImgePicker.ts +70 -0
  37. package/template/src/hooks/useSuggestionLocation.ts +36 -0
  38. package/template/src/hooks/useUploadProgress.ts +127 -0
  39. package/template/src/redux/api-config/baseApi.ts +89 -0
  40. package/template/src/redux/api-slices/authSlices.ts +175 -0
  41. package/template/src/redux/interface/common.ts +19 -0
  42. package/template/src/redux/interface/interface.ts +196 -0
  43. package/template/src/redux/interface/tag-types.ts +13 -0
  44. package/template/src/redux/service/demo.ts +27 -0
  45. package/template/src/redux/store.ts +17 -0
  46. package/template/src/utils/utils.ts +27 -0
@@ -0,0 +1,138 @@
1
+ import * as Yup from "yup";
2
+
3
+ import { ScrollView, View } from "react-native";
4
+
5
+ import { Icon } from "@/assets/icons/Icon";
6
+ import BackButton from "@/src/lib/backHeader/BackButton";
7
+ import TButton from "@/src/lib/buttons/TButton";
8
+ import InputText from "@/src/lib/inputs/InputText";
9
+ import tw from "@/src/lib/tailwind";
10
+ import { useChangePasswordMutation } from "@/src/redux/apiSlices/authSlices";
11
+ import { router } from "expo-router";
12
+ import { Formik } from "formik";
13
+ import React from "react";
14
+
15
+ // --- Icon Placeholders ---
16
+
17
+ // --- Yup Validation Schema ---
18
+ const ChangePasswordSchema = Yup.object().shape({
19
+ old_password: Yup.string().required("Current password is required"),
20
+ new_password: Yup.string()
21
+ .min(6, "Password must be at least 6 characters")
22
+ .required("New password is required")
23
+ .notOneOf(
24
+ [Yup.ref("old_password"), null],
25
+ "New password must be different from current password"
26
+ ),
27
+ c_password: Yup.string()
28
+ .oneOf([Yup.ref("new_password"), null], "Passwords must match")
29
+ .required("Please confirm your new password"),
30
+ });
31
+
32
+ // --- Reusable Password Input Component ---
33
+
34
+ // --- Main Change Password Screen Component ---
35
+ const ChangePasswordScreen = () => {
36
+ // const []
37
+
38
+ const [changePass, { isLoading }] = useChangePasswordMutation();
39
+
40
+ const handleSaveChanges = async (values: any) => {
41
+ try {
42
+ const res = await changePass(values).unwrap();
43
+
44
+ if (res?.success) {
45
+ router.push(
46
+ "/auth/change_pass_modal?title=You’re All Set!&subtitle=Your password has been changed successfully!&buttonTitle=Back"
47
+ );
48
+ } else {
49
+ router.push(`/modals/toaster?content=${res?.message}`);
50
+ }
51
+ } catch (error: any) {
52
+ router.push(`/modals/toaster?content=${error?.message}`);
53
+ }
54
+ };
55
+
56
+ return (
57
+ <Formik
58
+ initialValues={{
59
+ old_password: "",
60
+ new_password: "",
61
+ c_password: "",
62
+ }}
63
+ validationSchema={ChangePasswordSchema}
64
+ onSubmit={handleSaveChanges}
65
+ >
66
+ {({
67
+ handleChange,
68
+ handleBlur,
69
+ handleSubmit,
70
+ values,
71
+ errors,
72
+ touched,
73
+ }) => (
74
+ <View style={tw`flex-1 bg-[#121212]`}>
75
+ {/* Header */}
76
+ <BackButton
77
+ onPress={() => router.dismiss()}
78
+ title="Change Password"
79
+ />
80
+
81
+ <ScrollView contentContainerStyle={tw`p-5 mt-4 gap-5`}>
82
+ <InputText
83
+ textInputProps={{
84
+ placeholder: "Current Password",
85
+ placeholderTextColor: "#A9A9A9",
86
+ }}
87
+ variant="password"
88
+ svgFirstIcon={Icon.lock}
89
+ value={values.old_password}
90
+ errorText={errors.old_password}
91
+ touched={touched.old_password}
92
+ onChangeText={handleChange("old_password")}
93
+ onBlur={handleBlur("old_password")}
94
+ />
95
+
96
+ <InputText
97
+ textInputProps={{
98
+ placeholder: "New Password",
99
+ placeholderTextColor: "#A9A9A9",
100
+ }}
101
+ variant="password"
102
+ svgFirstIcon={Icon.lock}
103
+ value={values.new_password}
104
+ errorText={errors.new_password}
105
+ touched={touched.new_password}
106
+ onChangeText={handleChange("new_password")}
107
+ onBlur={handleBlur("new_password")}
108
+ />
109
+
110
+ <InputText
111
+ textInputProps={{
112
+ placeholder: "Confirm New Password",
113
+ placeholderTextColor: "#A9A9A9",
114
+ }}
115
+ variant="password"
116
+ svgFirstIcon={Icon.lock}
117
+ value={values.c_password}
118
+ errorText={errors.c_password}
119
+ touched={touched.c_password}
120
+ onChangeText={handleChange("c_password")}
121
+ onBlur={handleBlur("c_password")}
122
+ />
123
+ </ScrollView>
124
+
125
+ {/* Save Changes Button */}
126
+ <TButton
127
+ isLoading={isLoading}
128
+ onPress={handleSubmit}
129
+ containerStyle={tw`m-5`}
130
+ title="Save Changes"
131
+ />
132
+ </View>
133
+ )}
134
+ </Formik>
135
+ );
136
+ };
137
+
138
+ export default ChangePasswordScreen;
@@ -0,0 +1,74 @@
1
+ import { router, useGlobalSearchParams } from "expo-router";
2
+ import { Platform, Pressable, Text, View } from "react-native";
3
+
4
+ import { Icon } from "@/assets/icons/Icon";
5
+ import TButton from "@/src/lib/buttons/TButton";
6
+ import tw from "@/src/lib/tailwind";
7
+ import { BlurView } from "expo-blur";
8
+ import React from "react";
9
+ import { SvgXml } from "react-native-svg";
10
+
11
+ const Change_pass_modal = () => {
12
+ const params = useGlobalSearchParams();
13
+ // ?title='You’re All Set!'&subtitle='Your password has been changed successfully!'&buttonTitle='Back to login'&route='/auth
14
+ const { title, subtitle, buttonTitle, route }: any = params;
15
+ const CommonContent = () => {
16
+ return (
17
+ <View style={tw`items-center gap-5 w-full`}>
18
+ <SvgXml xml={Icon.check} />
19
+
20
+ <View style={tw`gap-2 w-full items-center`}>
21
+ <Text style={tw`text-white text-xl font-semibold text-center`}>
22
+ {title || "You’re All Set!"}
23
+ </Text>
24
+ <Text style={tw`text-gray-400 text-sm font-semibold text-center`}>
25
+ {subtitle || "Your password has been changed successfully!"}
26
+ </Text>
27
+ </View>
28
+
29
+ <TButton
30
+ containerStyle={tw`w-4/5 mt-3 self-center`}
31
+ onPress={() => {
32
+ router?.dismiss();
33
+ // router.push("/profile_setup");
34
+ if (route as string) {
35
+ router.push(route as any);
36
+ } else {
37
+ router?.dismiss();
38
+ }
39
+ }}
40
+ title={buttonTitle || "Back to login"}
41
+ />
42
+ </View>
43
+ );
44
+ };
45
+
46
+ return (
47
+ <Pressable
48
+ onPress={() => {
49
+ router.dismiss();
50
+ }}
51
+ style={tw`flex-1 bg-black/45 items-center justify-center`}
52
+ >
53
+ {Platform.OS === "ios" ? (
54
+ <BlurView
55
+ style={tw`w-[90%] h-[80] rounded-xl overflow-hidden items-center justify-center p-4`}
56
+ tint="dark"
57
+ blurReductionFactor={5}
58
+ intensity={100}
59
+ experimentalBlurMethod="dimezisBlurView"
60
+ >
61
+ <CommonContent />
62
+ </BlurView>
63
+ ) : (
64
+ <View
65
+ style={tw`w-[90%] h-[80] bg-black/85 border border-secondary rounded-xl overflow-hidden items-center justify-center p-4`}
66
+ >
67
+ <CommonContent />
68
+ </View>
69
+ )}
70
+ </Pressable>
71
+ );
72
+ };
73
+
74
+ export default Change_pass_modal;
@@ -0,0 +1,124 @@
1
+ import * as Yup from "yup";
2
+
3
+ import { Image, Text, View } from "react-native";
4
+
5
+ import AppBgWrapper from "@/src/components/common/AppBgWrapper";
6
+ import BackButton from "@/src/lib/backHeader/BackButton";
7
+ import { Formik } from "formik";
8
+ import { Icon } from "@/assets/icons/Icon";
9
+ import { ImageAssets } from "@/assets/images/image";
10
+ import InputText from "@/src/lib/inputs/InputText";
11
+ import { KeyboardAwareScrollView } from "react-native-keyboard-controller";
12
+ import React from "react";
13
+ import TButton from "@/src/lib/buttons/TButton";
14
+ import { router } from "expo-router";
15
+ import tw from "@/src/lib/tailwind";
16
+ import { useForgotMutation } from "@/src/redux/apiSlices/authSlices";
17
+
18
+ const Forgot = () => {
19
+ const [forgot, { isLoading }] = useForgotMutation();
20
+
21
+ const handleForgot = async (values: any) => {
22
+ try {
23
+ const res = await forgot(values).unwrap();
24
+ if (res?.success) {
25
+ router.push(`/modals/toaster?content=${res?.message}`);
26
+ router.replace(`/auth/opt_verify?email=${values.email}&forgot=true`);
27
+ } else {
28
+ router.push(`/modals/toaster?content=${res?.message}`);
29
+ }
30
+ } catch (error: any) {
31
+ router.push(`/modals/toaster?content=${error?.message}`);
32
+ }
33
+ };
34
+
35
+ // Define validation schema using Yup
36
+ const loginValidationSchema = Yup.object().shape({
37
+ email: Yup.string()
38
+ .email("Please enter a valid email")
39
+ .required("Email is required"),
40
+ });
41
+
42
+ return (
43
+ <AppBgWrapper>
44
+ <BackButton
45
+ onPress={() => router.dismiss()}
46
+ containerStyle={tw`absolute top-5`}
47
+ />
48
+ <KeyboardAwareScrollView
49
+ style={tw`z-10 flex-1`}
50
+ contentContainerStyle={tw`items-center justify-center flex-1`}
51
+ >
52
+ <View style={tw`z-10 flex-1 items-center justify-center p-5`}>
53
+ <View style={tw`justify-center items-center gap-2`}>
54
+ <Image
55
+ source={ImageAssets.logo}
56
+ style={tw`h-30 aspect-square mb-5`}
57
+ resizeMode="contain"
58
+ />
59
+ <View style={tw`items-center justify-center gap-2`}>
60
+ <Text
61
+ style={tw`text-white font-InterSemiBold text-2xl -tracking-[1px]`}
62
+ >
63
+ Forgot password ?
64
+ </Text>
65
+ <Text
66
+ style={tw`text-white text-base text-center font-InterRegular -tracking-[1px]`}
67
+ >
68
+ Enter the email address that you used to create your account. We
69
+ will send an OTP to reset your password.
70
+ </Text>
71
+ </View>
72
+ </View>
73
+
74
+ {/* Formik Wrapper */}
75
+ <Formik
76
+ initialValues={{ email: "" }}
77
+ validationSchema={loginValidationSchema}
78
+ onSubmit={handleForgot}
79
+ >
80
+ {({
81
+ handleChange,
82
+ handleBlur,
83
+ handleSubmit,
84
+ values,
85
+ errors,
86
+ touched,
87
+ isValid,
88
+ }) => (
89
+ <View style={tw`w-full py-8 gap-6`}>
90
+ <View style={tw`gap-3`}>
91
+ <InputText
92
+ svgFirstIcon={Icon.email}
93
+ textInputProps={{
94
+ placeholder: "Email",
95
+ placeholderTextColor: "#A9A9A9",
96
+ }}
97
+ value={values.email}
98
+ onChangeText={handleChange("email")}
99
+ onBlur={handleBlur("email")}
100
+ touched={touched.email}
101
+ errorText={errors.email}
102
+ />
103
+ </View>
104
+
105
+ {/* Submit button calls handleSubmit from Formik */}
106
+ <TButton
107
+ title="Get OTP"
108
+ isLoading={isLoading}
109
+ onPress={() => {
110
+ handleSubmit();
111
+ // router.push("/auth/opt_verify");
112
+ }}
113
+ disabled={!isValid}
114
+ />
115
+ </View>
116
+ )}
117
+ </Formik>
118
+ </View>
119
+ </KeyboardAwareScrollView>
120
+ </AppBgWrapper>
121
+ );
122
+ };
123
+
124
+ export default Forgot;
@@ -0,0 +1,274 @@
1
+ import * as Yup from "yup";
2
+
3
+ import {
4
+ useGoogleLoginMutation,
5
+ useLoginMutation,
6
+ } from "@/src/redux/apiSlices/authSlices";
7
+ import { Image, Text, TouchableOpacity, View } from "react-native";
8
+
9
+ import { Icon } from "@/assets/icons/Icon";
10
+ import { ImageAssets } from "@/assets/images/image";
11
+ import AppBgWrapper from "@/src/components/common/AppBgWrapper";
12
+ import IButton from "@/src/lib/buttons/IButton";
13
+ import Or from "@/src/lib/buttons/Or";
14
+ import TButton from "@/src/lib/buttons/TButton";
15
+ import CheckBox from "@/src/lib/inputs/CheckBox";
16
+ import InputText from "@/src/lib/inputs/InputText";
17
+ import tw from "@/src/lib/tailwind";
18
+ import { support } from "@/src/utils/utils";
19
+ import AsyncStorage from "@react-native-async-storage/async-storage";
20
+ import { router } from "expo-router";
21
+ import { Formik } from "formik";
22
+ import React from "react";
23
+ import { KeyboardAwareScrollView } from "react-native-keyboard-controller";
24
+ import { SvgXml } from "react-native-svg";
25
+
26
+ const Login = () => {
27
+ const [loginInfo, setLoginInfo] = React.useState<null | {
28
+ email: string;
29
+ password: string;
30
+ }>(null);
31
+ const [check, setCheck] = React.useState(false);
32
+ const [passShow, setPassShow] = React.useState(false);
33
+
34
+ const [login, results] = useLoginMutation();
35
+ const [loginWithGoogle, googleResults] = useGoogleLoginMutation();
36
+
37
+ const handleLogin = async (values: any) => {
38
+ try {
39
+ if (check) {
40
+ AsyncStorage.setItem("check", "true");
41
+ AsyncStorage.setItem("loginInfo", JSON.stringify(values));
42
+ } else {
43
+ AsyncStorage.removeItem("check");
44
+ AsyncStorage.removeItem("loginInfo");
45
+ }
46
+ const response = await login(values).unwrap();
47
+ if (response?.success) {
48
+ // console.log(response?.data);
49
+
50
+ await AsyncStorage.setItem("token", response?.data?.token);
51
+ router.replace("/auth/location_access");
52
+ } else {
53
+ router.push(`/modals/toaster?content=${response?.message}`);
54
+ }
55
+ } catch (error: any) {
56
+ console.log(error);
57
+ router.push(`/modals/toaster?content=${error?.message}`);
58
+ }
59
+ };
60
+
61
+ const handleLoginWithGoogle = async () => {
62
+ try {
63
+ const response = await loginWithGoogle({}).unwrap();
64
+ // console.log(response);
65
+ if (response?.success) {
66
+ // router.push("/home/tabs");
67
+ router.push(`/auth/google_login?url=${`${response?.data}`}`);
68
+ } else {
69
+ router.push(`/modals/toaster?content=${response?.message}`);
70
+ }
71
+ } catch (error: any) {
72
+ router.push(`/modals/toaster?content=${error?.message}`);
73
+ }
74
+ };
75
+
76
+ // Define validation schema using Yup
77
+ const loginValidationSchema = Yup.object().shape({
78
+ email: Yup.string()
79
+ .email("Please enter a valid email")
80
+ .required("Email is required"),
81
+ password: Yup.string()
82
+ .min(6, ({ min }) => `Password must be at least ${min} characters`)
83
+ .required("Password is required"),
84
+ });
85
+
86
+ React.useEffect(() => {
87
+ AsyncStorage.getItem("check").then((value) => {
88
+ if (value === "true") {
89
+ // console.log(value);
90
+ setCheck(true);
91
+ }
92
+ });
93
+ AsyncStorage.getItem("loginInfo").then((value) => {
94
+ if (value) {
95
+ // console.log(value);
96
+ setLoginInfo(JSON.parse(value));
97
+ }
98
+ });
99
+ }, []);
100
+
101
+ return (
102
+ <AppBgWrapper>
103
+ <KeyboardAwareScrollView style={tw`z-10 `}>
104
+ <View style={tw`flex-1 items-center justify-center p-5`}>
105
+ <View style={tw`justify-center items-center mt-10 gap-2`}>
106
+ <Image
107
+ source={ImageAssets.logo}
108
+ style={tw`h-18 aspect-square mb-5`}
109
+ resizeMode="contain"
110
+ />
111
+ <View style={tw`items-center justify-center gap-2`}>
112
+ <Text
113
+ style={tw`text-white font-InterSemiBold text-2xl -tracking-[1px]`}
114
+ >
115
+ Welcome Back
116
+ </Text>
117
+ <Text
118
+ style={tw`text-white text-base font-InterRegular -tracking-[1px]`}
119
+ >
120
+ Please use your credentials to sign in
121
+ </Text>
122
+ </View>
123
+ </View>
124
+
125
+ {/* Formik Wrapper */}
126
+ <Formik
127
+ initialValues={{
128
+ email: loginInfo?.email || "",
129
+ password: loginInfo?.password || "",
130
+ }}
131
+ enableReinitialize
132
+ validationSchema={loginValidationSchema}
133
+ onSubmit={handleLogin}
134
+ >
135
+ {({
136
+ handleChange,
137
+ handleBlur,
138
+ handleSubmit,
139
+ values,
140
+ errors,
141
+ touched,
142
+ isValid,
143
+ }) => (
144
+ <View style={tw`w-full py-8 gap-6`}>
145
+ <View style={tw`gap-3`}>
146
+ <InputText
147
+ svgFirstIcon={Icon.email}
148
+ textInputProps={{
149
+ placeholder: "Email",
150
+ placeholderTextColor: "#A9A9A9",
151
+ }}
152
+ value={values.email}
153
+ onChangeText={handleChange("email")}
154
+ onBlur={handleBlur("email")}
155
+ touched={touched.email}
156
+ errorText={errors.email}
157
+ />
158
+
159
+ <InputText
160
+ svgFirstIcon={Icon.lock}
161
+ textInputProps={{
162
+ placeholder: "Password",
163
+ placeholderTextColor: "#A9A9A9",
164
+ secureTextEntry: !passShow,
165
+ }}
166
+ value={values.password}
167
+ onChangeText={handleChange("password")}
168
+ onBlur={handleBlur("password")}
169
+ touched={touched.password}
170
+ errorText={errors.password}
171
+ svgSecondIcon={passShow ? Icon.eye : Icon.eyeOff}
172
+ svgSecondOnPress={() => setPassShow(!passShow)}
173
+ />
174
+ </View>
175
+
176
+ <View style={tw`flex-row justify-between items-center`}>
177
+ <View style={tw`flex-row items-center`}>
178
+ <CheckBox
179
+ checked={check}
180
+ onPress={() => setCheck(!check)}
181
+ title="Remember me"
182
+ />
183
+ </View>
184
+ <TouchableOpacity
185
+ onPress={() => {
186
+ router.push("/auth/forgot");
187
+ }}
188
+ >
189
+ <Text style={tw`text-[#339DFF] underline`}>
190
+ Forgot Password?
191
+ </Text>
192
+ </TouchableOpacity>
193
+ </View>
194
+
195
+ {/* Submit button calls handleSubmit from Formik */}
196
+ <TButton
197
+ isLoading={results.isLoading}
198
+ title="Sign In"
199
+ onPress={() => {
200
+ handleSubmit();
201
+ // router.push("/home");
202
+ }}
203
+ disabled={!isValid}
204
+ />
205
+
206
+ <Or title="Or continue with" />
207
+ <View style={tw`flex-row justify-center items-center gap-4`}>
208
+ <IButton
209
+ isLoading={googleResults.isLoading}
210
+ containerStyle={tw`w-16 h-16 bg-transparent `}
211
+ svg={Icon.google}
212
+ onPress={handleLoginWithGoogle}
213
+ />
214
+ {/* <IButton
215
+ containerStyle={tw`w-16 h-16 bg-transparent `}
216
+ svg={Icon.apple}
217
+ onPress={handleLoginWithGoogle}
218
+ /> */}
219
+ </View>
220
+
221
+ <View style={tw`gap-2`}>
222
+ <View style={tw`flex-row justify-center `}>
223
+ <Text style={tw`text-white`}>Dont have an account?</Text>
224
+ <TouchableOpacity
225
+ onPress={() => {
226
+ router.push("/auth/register");
227
+ }}
228
+ style={tw`flex-row items-center gap-3`}
229
+ >
230
+ <Text style={tw`text-[#339DFF] underline ml-1`}>
231
+ Sign up
232
+ </Text>
233
+ <SvgXml xml={Icon.play} />
234
+ </TouchableOpacity>
235
+ </View>
236
+ <View>
237
+ <Text style={tw`text-white text-center leading-6`}>
238
+ Please read our{" "}
239
+ <Text
240
+ onPress={() =>
241
+ router.push("/settings/terms_and_conditions")
242
+ }
243
+ style={tw`text-[#339DFF] underline`}
244
+ >
245
+ Terms
246
+ </Text>{" "}
247
+ and{" "}
248
+ <Text
249
+ onPress={() => router.push("/settings/privacy_policy")}
250
+ style={tw`text-[#339DFF] underline`}
251
+ >
252
+ Privacy Policy
253
+ </Text>{" "}
254
+ and if you have any problems please contact our{" "}
255
+ <Text
256
+ onPress={() => support()}
257
+ style={tw`text-[#339DFF] underline`}
258
+ >
259
+ Support
260
+ </Text>
261
+ </Text>
262
+ </View>
263
+ </View>
264
+ </View>
265
+ )}
266
+ </Formik>
267
+ {/* End of Formik Wrapper */}
268
+ </View>
269
+ </KeyboardAwareScrollView>
270
+ </AppBgWrapper>
271
+ );
272
+ };
273
+
274
+ export default Login;