From a4fa09589eb3fe6570dddb60e986d289750497b9 Mon Sep 17 00:00:00 2001 From: b3ni15 Date: Mon, 28 Jul 2025 00:00:07 +0200 Subject: [PATCH] Implement login functionality and create profile screen with secure storage --- app/index.tsx | 143 +++++++++++++++++++----------------------------- app/profile.tsx | 76 +++++++++++++++++++++++++ package.json | 2 + pnpm-lock.yaml | 73 ++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 88 deletions(-) create mode 100644 app/profile.tsx diff --git a/app/index.tsx b/app/index.tsx index 70f10c9..42ef62b 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -1,85 +1,77 @@ -import * as Notifications from 'expo-notifications'; +import axios from 'axios'; +import { useRouter } from 'expo-router'; +import * as SecureStore from 'expo-secure-store'; import { StatusBar } from 'expo-status-bar'; -import React, { useEffect, useState } from "react"; -import { Alert, Platform, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native"; +import React, { useState } from "react"; +import { ActivityIndicator, Alert, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native"; const PRIMARY = '#A24BFA'; const BG = '#0c0a0a'; -Notifications.setNotificationHandler({ - handleNotification: async () => ({ - shouldShowBanner: true, - shouldShowList: true, - shouldPlaySound: false, - shouldSetBadge: false, - }) -}); - -async function registerForPushNotificationsAsync() { - const { status: existingStatus } = await Notifications.getPermissionsAsync(); - let finalStatus = existingStatus; - if (existingStatus !== 'granted') { - const { status } = await Notifications.requestPermissionsAsync(); - finalStatus = status; - } - if (finalStatus !== 'granted') { - Alert.alert('Permission for notifications not granted!'); - return false; - } - return true; -} - -async function sendNotification() { - try { - const id = await Notifications.scheduleNotificationAsync({ - content: { - title: "Hello!", - body: "Ez egy értesítés példája.", - }, - trigger: Platform.OS === 'android' - ? ({ seconds: 1, repeats: false } as any) - : null, - }); - Alert.alert('Notification scheduled!', `ID: ${id}`); - } catch (e) { - Alert.alert('Hiba történt!', String(e)); - } -} - export default function Index() { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); + const [loading, setLoading] = useState(false); + const router = useRouter(); - useEffect(() => { - registerForPushNotificationsAsync(); - }, []); + async function handleLogin() { + setLoading(true); + console.log('Login attempt:', username); + try { + const response = await axios.post( + "https://mymenu.mcdonalds.hu/api/AccountApi/Login", + { + Data: { + UserName: username, + Password: password + } + }, + { + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'referer': 'https://mymenu.mcdonalds.hu/', + 'origin': 'https://mymenu.mcdonalds.hu' + } + } + ); + console.log('Login response:', response.data, response.headers); + const cookie = response.headers['set-cookie']?.join('; '); + const userId = response.data.Data.UserID; + const fullName = response.data.Data.FullName; + await SecureStore.setItemAsync('cookie', cookie || ''); + await SecureStore.setItemAsync('userId', String(userId)); + await SecureStore.setItemAsync('email', username); + await SecureStore.setItemAsync('password', password); + await SecureStore.setItemAsync('fullName', fullName || ''); + console.log('Saved to SecureStore:', { cookie, userId, username, password, fullName }); + router.replace('/profile'); + } catch (e) { + console.log('Login error:', e); + Alert.alert('Hiba', 'Hibás felhasználónév vagy jelszó, vagy hálózati hiba.'); + } finally { + setLoading(false); + } + } return ( - - ANGELIC{"\n"}MC - Üdv újra - Jelentkezz be a fiókodba + Jelentkezz be a mymenu fiókodba Felhasználónév - - Jelszó - - Elfelejtetted? - - + Jelszó - - Bejelentkezés + + {loading ? ( + + ) : ( + Bejelentkezés + )} - - - Nincs még fiókod? - - Regisztrálj most! - - ); @@ -127,14 +116,6 @@ const styles = StyleSheet.create({ shadowOffset: { width: 0, height: 8 }, elevation: 8, }, - logoText: { - color: PRIMARY, - fontWeight: 'bold', - fontSize: 28, - textAlign: 'center', - letterSpacing: 2, - marginBottom: 4, - }, title: { color: '#fff', fontWeight: 'bold', @@ -163,11 +144,6 @@ const styles = StyleSheet.create({ paddingVertical: 12, fontSize: 16, }, - forgot: { - color: PRIMARY, - fontSize: 14, - fontWeight: '500', - }, button: { backgroundColor: PRIMARY, borderRadius: 12, @@ -185,13 +161,4 @@ const styles = StyleSheet.create({ fontWeight: 'bold', fontSize: 18, }, - bottomText: { - color: '#bdbdbd', - fontSize: 15, - }, - register: { - color: PRIMARY, - fontWeight: 'bold', - fontSize: 15, - }, }); \ No newline at end of file diff --git a/app/profile.tsx b/app/profile.tsx new file mode 100644 index 0000000..ef504b0 --- /dev/null +++ b/app/profile.tsx @@ -0,0 +1,76 @@ +import * as SecureStore from 'expo-secure-store'; +import React, { useEffect, useState } from "react"; +import { StyleSheet, Text, View } from "react-native"; + +const PRIMARY = '#A24BFA'; +const BG = '#0c0a0a'; + +export default function Profile() { + const [fullName, setFullName] = useState(''); + const [email, setEmail] = useState(''); + const [userId, setUserId] = useState(''); + + useEffect(() => { + (async () => { + const name = await SecureStore.getItemAsync('fullName'); + const mail = await SecureStore.getItemAsync('email'); + const uid = await SecureStore.getItemAsync('userId'); + setFullName(name || ''); + setEmail(mail || ''); + setUserId(uid || ''); + })(); + }, []); + + return ( + + Profil + + Név: + {fullName} + Email: + {email} + UserID: + {userId} + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: BG, + justifyContent: 'center', + alignItems: 'center', + }, + title: { + color: '#fff', + fontWeight: 'bold', + fontSize: 28, + textAlign: 'center', + marginBottom: 24, + }, + card: { + backgroundColor: 'rgba(24, 20, 28, 0.95)', + borderRadius: 24, + padding: 32, + width: '90%', + maxWidth: 400, + shadowColor: '#000', + shadowOpacity: 0.3, + shadowRadius: 24, + shadowOffset: { width: 0, height: 8 }, + elevation: 8, + }, + label: { + color: '#bdbdbd', + fontSize: 16, + marginTop: 12, + fontWeight: 'bold', + }, + value: { + color: PRIMARY, + fontSize: 18, + marginBottom: 8, + }, +}); diff --git a/package.json b/package.json index f739e11..9bbec04 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@react-navigation/bottom-tabs": "^7.3.10", "@react-navigation/elements": "^2.3.8", "@react-navigation/native": "^7.1.6", + "axios": "^1.11.0", "expo": "~53.0.20", "expo-blur": "~14.1.5", "expo-constants": "~17.1.7", @@ -24,6 +25,7 @@ "expo-linking": "~7.1.7", "expo-notifications": "~0.31.4", "expo-router": "~5.1.4", + "expo-secure-store": "^14.2.3", "expo-splash-screen": "~0.30.10", "expo-status-bar": "~2.2.3", "expo-symbols": "~0.4.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c136520..d78cc9c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: '@react-navigation/native': specifier: ^7.1.6 version: 7.1.16(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) + axios: + specifier: ^1.11.0 + version: 1.11.0 expo: specifier: ~53.0.20 version: 53.0.20(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) @@ -47,6 +50,9 @@ importers: expo-router: specifier: ~5.1.4 version: 5.1.4(e1c8eefe113e01b6d50ed7cbca38deea) + expo-secure-store: + specifier: ^14.2.3 + version: 14.2.3(expo@53.0.20(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)) expo-splash-screen: specifier: ~0.30.10 version: 0.30.10(expo@53.0.20(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)) @@ -1347,10 +1353,16 @@ packages: async-limiter@1.0.1: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + axios@1.11.0: + resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==} + babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1569,6 +1581,10 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -1693,6 +1709,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -2032,6 +2052,11 @@ packages: react-native-reanimated: optional: true + expo-secure-store@14.2.3: + resolution: {integrity: sha512-hYBbaAD70asKTFd/eZBKVu+9RTo9OSTMMLqXtzDF8ndUGjpc6tmRCoZtrMHlUo7qLtwL5jm+vpYVBWI8hxh/1Q==} + peerDependencies: + expo: '*' + expo-splash-screen@0.30.10: resolution: {integrity: sha512-Tt9va/sLENQDQYeOQ6cdLdGvTZ644KR3YG9aRlnpcs2/beYjOX1LHT510EGzVN9ljUTg+1ebEo5GGt2arYtPjw==} peerDependencies: @@ -2155,6 +2180,15 @@ packages: flow-enums-runtime@0.0.6: resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + fontfaceobserver@2.3.0: resolution: {integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==} @@ -2166,6 +2200,10 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + freeport-async@2.0.0: resolution: {integrity: sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==} engines: {node: '>=8'} @@ -3141,6 +3179,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -5628,10 +5669,20 @@ snapshots: async-limiter@1.0.1: {} + asynckit@0.4.0: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 + axios@1.11.0: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.4 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + babel-jest@29.7.0(@babel/core@7.28.0): dependencies: '@babel/core': 7.28.0 @@ -5917,6 +5968,10 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@12.1.0: {} commander@2.20.3: {} @@ -6041,6 +6096,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delayed-stream@1.0.0: {} + depd@2.0.0: {} destroy@1.2.0: {} @@ -6514,6 +6571,10 @@ snapshots: - react-native - supports-color + expo-secure-store@14.2.3(expo@53.0.20(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)): + dependencies: + expo: 53.0.20(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) + expo-splash-screen@0.30.10(expo@53.0.20(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.5(@babel/core@7.28.0)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)): dependencies: '@expo/prebuild-config': 9.0.11 @@ -6667,6 +6728,8 @@ snapshots: flow-enums-runtime@0.0.6: {} + follow-redirects@1.15.9: {} + fontfaceobserver@2.3.0: {} for-each@0.3.5: @@ -6678,6 +6741,14 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + freeport-async@2.0.0: {} fresh@0.5.2: {} @@ -7744,6 +7815,8 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + proxy-from-env@1.1.0: {} + punycode@2.3.1: {} qrcode-terminal@0.11.0: {}