diff --git a/README.md b/README.md index 1fa84a6..c8e7d0e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ --- -  ![Redux](https://img.shields.io/badge/Redux-593D88?style=for-the-badge&logo=redux&logoColor=white)   ![Docker](https://img.shields.io/badge/Docker-2496ED.svg?style=for-the-badge&logo=Docker&logoColor=white)   ![React Native](https://img.shields.io/badge/React_Native-20232A?style=for-the-badge&logo=react&logoColor=61DAFB)   ![Spotify Api](https://img.shields.io/badge/Spotify-1ED760?&style=for-the-badge&logo=spotify&logoColor=white) @@ -34,9 +33,9 @@ La racine de notre gitlab est composée de deux dossiers essentiels au projet: -[**src**](src) : **Toute la partie codage de l'application mobile** (contient un dossier API pour l'API FLAD qui effectue les requêtes vers l'API SPOTIFY et la base de données, ainsi qu'un dossier FLAD qui contient toute la partie côté client de l'application) +[**src**](src) : **Ensemble du code pour l'application mobile et les services web** (Application React Native, API Express en TypeScript, et messagerie MQTT) -[**doc**](doc) : **Documentation de l'application** (contient les maquettes) +[**doc**](doc) : **Documentation de l'application** (Inclut des diagrammes, des maquettes et des images) ## Fonctionnement @@ -62,11 +61,11 @@ Pour la suite, il suffit seulement de vérifier que node.js est à jour et insta Maintenant vous pouvez à tout moment lancer l'application grâce à la commande : **npx expo start :sunglasses:**
-:information_source: *Cliquer sur la touche 'w' si vous voulez le visualiser sur un navigateur (ce que je ne conseille pas) ou installer l'application 'Expo go' de votre téléphone et scanner le QR code proposer pour le visualiser (à noter que l'ordinateur dans lequel il se voit lancer doit être dans le même réseau local que votre téléphone)* +:information_source: *N'oubliez pas d'installer 'Expo Go' depuis le store de votre téléphone.* -- ### Comment le lancer à partir de l'iut d'Aubière ? +- ### Comment le lancer à partir de l'IUT d'Aubière ? -Cela est un peu plus difficile mais faisable !!! +Cela est un peu plus difficile mais faisable !
Tout d'abord aller dans votre compte scratch : **cd home/scratch/compte** @@ -89,11 +88,10 @@ Et entrer la commande : **export NODE_OPTIONS=--openssl-legacy-provider** Maintenant vous pouvez à tout moment lancer l'application grâce à la commande : **npx expo start :sunglasses:**
-:information_source: *Cliquer sur la touche 'w' si vous voulez le visualiser sur un navigateur (ce que je ne conseille pas) ou installer l'application 'Expo go' de votre téléphone et scanner le QR code proposer pour le visualiser (à noter que l'ordinateur dans lequel il se voit lancer doit être dans le même réseau local que votre téléphone)* - ### Comment s'inscrire sur l'application ? -Tout d'abord, il faut fournir votre *adresse e-mail* et votre *nom Spotify* aux **techniciens de l'application** (voir plus bas). Ils s'occuperont de vous ajouter définitivement à l'application. Une fois que cela est fait, inscrivez-vous via la **page d'inscription** de l'application en cliquant d'abord sur le bouton 'lier mon compte': +Tout d'abord, il faut fournir votre *adresse e-mail* et votre *nom Spotify* aux **techniciens de l'application** (voir plus bas). Ils s'occuperont de vous ajouter définitivement à l'application. Une fois que cela est fait, inscrivez-vous via la **page d'inscription** de l'application :
@@ -102,7 +100,7 @@ Tout d'abord, il faut fournir votre *adresse e-mail* et votre *nom Spotify* aux
-Vous serez normalement redirigé sur la page Spotify où vous devrez vous connecter. Une fois connecté, entrez votre nom, votre adresse e-mail et votre mot de passe en tant qu'utilisateur FLAD (n'oubliez pas ces informations car vous en aurez besoin pour vous connecter). Ensuite, cliquez sur le bouton ```suivant``` et bienvenue sur l'application ! +Une fois sur la page, saisissez votre nom, votre adresse e-mail, et votre mot de passe en tant qu'utilisateur FLAD (n'oubliez pas ces informations, vous en aurez besoin pour vous connecter). Pour lier votre compte à Spotify, vous serez automatiquement redirigé vers la page de connexion Spotify. Entrez vos identifiants Spotify, puis cliquez sur le bouton ```Suivant``` et bienvenue sur l'application !" ## Visuel de l'Application @@ -114,8 +112,13 @@ Vous serez normalement redirigé sur la page Spotify où vous devrez vous connec :information_source: Lorsque vous entrez dans notre application, la page d'accueil (**home**) vous permet de découvrir les musiques :notes: des utilisateurs autour de vous. Vous pouvez valider une musique soit en cliquant sur le bouton, soit en la glissant vers la droite :point_up_2:. Cette musique sera alors ajoutée à la page **favoris** :heart: et vous pourrez entamer une discussion avec l'utilisateur dans la page **chat** :speech_balloon:.
-Dans la page **settings** ⚙️, vous avez accès à toutes vos informations ```Spotify```, que vous pouvez modifier à votre guise. Toutefois, ces modifications ne seront prises en compte que dans notre application. Vous pouvez également choisir le mode sombre (dark mode) dans les paramètres pour une expérience de navigation plus confortable. + +Pour accéder aux détails d'une musique, maintenez votre doigt appuyé sur un Spot ou rendez-vous sur la page des favoris. Vous pourrez écouter la musique :arrow_forward:, obtenir des informations sur l'artiste et la chanson, découvrir des musiques similaires, et même l'ajouter à votre playlist Spotify ou la partager. +
+`Dans la page **settings** ⚙️, vous avez accès à toutes vos informations ```Spotify```, que vous pouvez modifier à votre guise. Toutefois, ces modifications ne seront prises en compte que dans notre application. Vous pouvez également choisir le mode sombre (dark mode) dans les paramètres pour une expérience de navigation plus confortable. +
+ ### Voici un petit récapitulatif
@@ -125,9 +128,9 @@ Dans la page **settings** ⚙️, vous avez accès à toutes vos informations `` - - - + + +
Button 3
Suprimer de la pile un spotAjout Discover (pour l'instant il permet d'ajouter des spot suplémentaires dans la pile pour que vous puissiez vous amusez si il n'y aucun utilisateur à coté de vous)Like pour ajouter au favorieSupprimer de la pile un spotAjout dans une playlist de votre compte Spotify (créée spécialement par l'application)Ajouter à vos favoris
diff --git a/src/Api/src/controllers/spotifyController.ts b/src/Api/src/controllers/spotifyController.ts index 57252f6..42a75b0 100644 --- a/src/Api/src/controllers/spotifyController.ts +++ b/src/Api/src/controllers/spotifyController.ts @@ -1,6 +1,5 @@ import IController from './interfaces/IController'; -import { Router, Request, Response, NextFunction } from 'express'; -import HttpException from '../exception/HttpException'; +import { Router, Request, Response } from 'express'; import axios from 'axios'; import qs from 'qs'; @@ -98,8 +97,7 @@ class SpotifyController implements IController { private login = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const redirectResponse = req.query.redirectUrl ? req.query.redirectUrl : req.headers.referer; @@ -112,14 +110,13 @@ class SpotifyController implements IController { redirect_uri: this.CALLBACK, })); } catch (error) { - next(new HttpException(400, "Cannot connect: " + error.message)); + res.status(400).send('Cannot connect: ' + error.message); } }; private getRefreshToken = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { const params = req.query.refresh_token; if (!req.query.refresh_token) { @@ -158,8 +155,7 @@ class SpotifyController implements IController { private getAccessToken = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { let code = req.query.code; let storedRedirectUri = req.cookies ? req.cookies[this.clientRedirect] : null; @@ -192,7 +188,7 @@ class SpotifyController implements IController { })); } } catch (error) { - next(new HttpException(400, 'Error connection: ' + error.message)); + res.status(400).send('Error connection: ' + error.message); } }; } diff --git a/src/Api/src/controllers/userController.ts b/src/Api/src/controllers/userController.ts index 4f2b823..92956fe 100644 --- a/src/Api/src/controllers/userController.ts +++ b/src/Api/src/controllers/userController.ts @@ -1,6 +1,5 @@ import { Router, Request, Response, NextFunction } from 'express'; import IController from './interfaces/IController'; -import HttpException from '../exception/HttpException'; import User from '../models/User'; import UserService from '../services/UserService'; import validator from '../middlewares/UserValidation' @@ -363,6 +362,38 @@ class UserController implements IController { */ this.router.put(`${this.path}/email`, authenticator, this.setEmail); + /** + * @swagger + * /api/user/spotify: + * put: + * summary: Update the spotify account + * description: Update the spotify account of the authenticated user + * tags: + * - User + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * tokenSpotify: + * type: string + * description: Spotify token + * responses: + * 200: + * description: Spotify account updated successfully + * 401: + * description: Unauthorized - Invalid or missing authentication token + * 409: + * description: Conflict - The provided token is already in use by another user + * 500: + * description: Internal Server Error - Spotify account not authorized or not found + */ + this.router.put(`${this.path}/spotify`, authenticator, this.setSpotify); + /** * @swagger * /api/user/image: @@ -430,8 +461,7 @@ class UserController implements IController { private register = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { let access_token; @@ -489,36 +519,33 @@ class UserController implements IController { ); res.status(201).json({ token }); } catch (error: any) { - next(new HttpException(409, error.message)); + res.status(409).json(error.message); } }; private login = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const { email, password } = req.body; const token = await this.userService.login(email, password); res.status(200).json({ token }); } catch (error: any) { - next(new HttpException(400, error.message)); + res.status(400).json(error.message) } }; private getUser = ( req: Request, - res: Response, - next: NextFunction + res: Response ): Response | void => { res.status(200).send({ data: req.user }); }; private getUsers = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { const userIds = req.query.ids as string; @@ -538,22 +565,21 @@ class UserController implements IController { private deleteUser = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const { _id } = req.user; await this.userService.delete(_id); + await this.locationService.delete(_id); res.status(204).send(); } catch (error: any) { - next(new HttpException(404, error.message)); + res.status(404).json(error.message) } }; private getUserNext = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const longitude = Number(req.query.longitude); @@ -568,14 +594,13 @@ class UserController implements IController { res.status(201).send(data); } catch (error: any) { - next(new HttpException(400, 'Cannot create get netUser: ' + error.message)); + res.status(400).json(error.message) } } private deleteMusic = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const { _id } = req.user; @@ -593,14 +618,13 @@ class UserController implements IController { } } catch (error: any) { - next(new HttpException(404, error.message)); + res.status(404).json(error.message) } } private addMusic = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const { _id } = req.user; @@ -616,28 +640,26 @@ class UserController implements IController { await this.userService.addMusic(_id, music); res.status(201).send({ music }); } catch (error: any) { - next(new HttpException(400, error.message)); + res.status(400).json(error.message) } } private getMusics = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const userId: string = req.user.id; const musics = await this.userService.getMusics(userId); return res.status(200).json({ musics }); } catch (error: any) { - next(new HttpException(400, error.message)); + res.status(400).json(error.message) } } private setName = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const { _id } = req.user; @@ -652,14 +674,13 @@ class UserController implements IController { res.status(200).json({ message: 'Name updated successfully' }); } catch (error: any) { - next(new HttpException(409, error.message)); + res.status(409).json(error.message) } } private setEmail = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const { _id } = req.user; @@ -674,14 +695,74 @@ class UserController implements IController { res.status(200).json({ message: 'Email updated successfully' }); } catch (error: any) { - next(new HttpException(409, error.message)); + res.status(409).json(error.message) + } + } + + private setSpotify = async ( + req: Request, + res: Response + ): Promise => { + let access_token; + let idAccount: string; + let image: string; + const { _id, idSpotify } = req.user; + const { tokenSpotify } = req.body; + + if (!tokenSpotify) { + return res.status(400).json({ error: 'TokenSpotify is missing in the request.' }); + } + + const apiBaseUrl = process.env.API_BASE_URL || 'http://localhost:8080/api'; + const refreshUrl = `${apiBaseUrl}/spotify/refresh?refresh_token=${tokenSpotify}`; + try { + const authOptions = { + method: 'GET', + url: refreshUrl, + json: true + }; + const authResponse = await axios(authOptions); + if (authResponse.status === 200) { + access_token = authResponse.data.access_token; + const headers = { + Authorization: `Bearer ${access_token}`, + }; + const resp = await axios.get('https://api.spotify.com/v1/me', { headers }); + if (resp.status == 200) { + const images = resp.data.images; + idAccount = resp.data.id; + if (idSpotify === idAccount) { + return res.status(400).json({ error: 'idSpotify cannot be the same as idAccount.' }); + } + if (images && images.length > 0) { + images.sort((a: any, b: any) => b.height - a.height); + image = images[0].url; + } + else { + const imagePath = './src/assets/images/default_user.png'; + const imageBuffer = fs.readFileSync(imagePath); + const base64Image = 'data:image/png;base64,' + base64js.fromByteArray(imageBuffer); + image = base64Image + } + } + } + } catch (error: any) { + console.log(error); + res.status(500).send("Internal Server Error: Unable to authenticate with Spotify"); + return; + } + try { + await this.userService.setSpotify(_id, tokenSpotify, idAccount, image); + + res.status(200).json({ message: 'Spotify token updated successfully' }); + } catch (error: any) { + res.status(409).json(error.message) } } private setImage = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const { _id } = req.user; @@ -691,14 +772,13 @@ class UserController implements IController { res.status(200).json({ message: 'Image updated successfully' }); } catch (error: any) { - next(new HttpException(500, error.message)); + res.status(500).json(error.message) } } private setPassword = async ( req: Request, - res: Response, - next: NextFunction + res: Response ): Promise => { try { const { _id } = req.user; @@ -708,7 +788,7 @@ class UserController implements IController { res.status(200).json({ message: 'Password updated successfully' }); } catch (error: any) { - next(new HttpException(500, error.message)); + res.status(500).json(error.message) } } } diff --git a/src/Api/src/services/UserService.ts b/src/Api/src/services/UserService.ts index 61efa79..61636bc 100644 --- a/src/Api/src/services/UserService.ts +++ b/src/Api/src/services/UserService.ts @@ -64,7 +64,7 @@ class UserService { if (validIds.length === 0) { return []; } - + return await this.user.find({ _id: { $in: validIds } }) .select('_id name image') } catch (error: any) { @@ -129,6 +129,21 @@ class UserService { } } + public async setSpotify(userId: string, tokenSpotify: string, idSpotify: string, image: string): Promise { + try { + await this.user.findByIdAndUpdate( + userId, + { + tokenSpotify: tokenSpotify, + idSpotify: idSpotify, + image: image + } + ); + } catch (error) { + throw new Error(error.message); + } + } + public async setImage(userId: string, newImage: string): Promise { try { await this.user.findByIdAndUpdate( diff --git a/src/FLAD/components/UserInfoBadgeComponent.tsx b/src/FLAD/components/UserInfoBadgeComponent.tsx index 0f8b06a..5afe566 100644 --- a/src/FLAD/components/UserInfoBadgeComponent.tsx +++ b/src/FLAD/components/UserInfoBadgeComponent.tsx @@ -17,7 +17,7 @@ export default function UserInfoBadge(props: UserInfoProps) { paddingHorizontal: normalize(10), backgroundColor: '#3F1DC3', alignSelf: 'flex-start', - borderRadius: 12, + borderRadius: 10, paddingRight: 20, }, section: { diff --git a/src/FLAD/package.json b/src/FLAD/package.json index ad8f205..e42515b 100644 --- a/src/FLAD/package.json +++ b/src/FLAD/package.json @@ -38,6 +38,7 @@ "react-native-screens": "~3.18.0", "react-native-svg": "13.4.0", "react-navigation-shared-element": "^3.1.3", + "react-native-web": "~0.18.9", "react-redux": "^8.0.5", "redux": "^4.2.1" }, @@ -48,4 +49,4 @@ "typescript": "^4.6.3" }, "private": true -} \ No newline at end of file +} diff --git a/src/FLAD/redux/thunk/authThunk.tsx b/src/FLAD/redux/thunk/authThunk.tsx index 1f29bbc..74114e0 100644 --- a/src/FLAD/redux/thunk/authThunk.tsx +++ b/src/FLAD/redux/thunk/authThunk.tsx @@ -39,7 +39,18 @@ export const register = (registerCredential: RegisterCredentials) => { dispatch(setErrorSignup("Email non valide !")); break; case 409: - dispatch(setErrorSignup("Email, Spotify ou nom déjà utilisé !")); + const duplicateFields = error.response.data || []; + let errorMessage = "Email, Spotify ou nom déjà utilisé !"; + if (duplicateFields.includes('idSpotify')) { + errorMessage = "Compte Spotify déjà utilisé !"; + } + if (duplicateFields.includes('name')) { + errorMessage = "Nom déjà utilisé !"; + } + if (duplicateFields.includes('email')) { + errorMessage = "Email déjà utilisé !"; + } + dispatch(setErrorSignup(errorMessage)); break; case 500: dispatch(setErrorSignup("Compte Spotify non autorisé !")); diff --git a/src/FLAD/redux/thunk/userThunk.tsx b/src/FLAD/redux/thunk/userThunk.tsx index 4ded97f..206de67 100644 --- a/src/FLAD/redux/thunk/userThunk.tsx +++ b/src/FLAD/redux/thunk/userThunk.tsx @@ -3,6 +3,7 @@ import configs from "../../constants/config"; import { setDarkMode, setErrorUpdateMessage, userLogin } from "../actions/userActions"; import * as SecureStore from 'expo-secure-store'; import { UserMapper } from "../../models/mapper/UserMapper"; +import { MusicServiceProvider } from "../../models/MusicServiceProvider"; export const darkMode = (value: boolean) => { //@ts-ignore @@ -119,4 +120,39 @@ export const setImage = (image: string) => { } } } +} + +export const setSpotify = (tokenSpotify: string) => { + //@ts-ignore + return async dispatch => { + try { + let token: string | null = await SecureStore.getItemAsync(configs.key); + const headers = { + 'Authorization': 'Bearer ' + token + }; + await axios.put(configs.API_URL + '/user/spotify', { tokenSpotify }, { headers }); + + const user = await axios.get( + configs.API_URL + '/user', + { headers } + ) + MusicServiceProvider.initSpotify(user.data.data.tokenSpotify, user.data.data.idSpotify); + dispatch(userLogin(UserMapper.toModel(user.data.data))); + } catch (error: any) { + switch (error.response.status) { + case 400: + dispatch(setErrorUpdateMessage("Ce compte Spotify est déjà associé à votre compte.")) + break; + case 409: + dispatch(setErrorUpdateMessage("Compte Spotify déjà utilisé !")) + break; + case 500: + dispatch(setErrorUpdateMessage("Compte Spotify non autorisé !")); + break; + default: + console.error("Error : " + error.message); + break; + } + } + } } \ No newline at end of file diff --git a/src/FLAD/screens/DetailScreen.tsx b/src/FLAD/screens/DetailScreen.tsx index 4e39f1c..dbdd212 100644 --- a/src/FLAD/screens/DetailScreen.tsx +++ b/src/FLAD/screens/DetailScreen.tsx @@ -1,5 +1,5 @@ import { useIsFocused, useNavigation } from "@react-navigation/native"; -import { View, Text, Image, StyleSheet, TouchableOpacity, ScrollView, Share, Alert, Linking, FlatList, ActivityIndicator, Platform, SafeAreaView } from "react-native"; +import { View, Text, Image, StyleSheet, TouchableOpacity, ScrollView, Share, Alert, Linking, FlatList, ActivityIndicator, Platform } from "react-native"; import Animated, { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, withSpring } from "react-native-reanimated"; import { Audio } from 'expo-av'; import { useEffect, useState } from "react"; diff --git a/src/FLAD/screens/ProfilScreen.tsx b/src/FLAD/screens/ProfilScreen.tsx index 088695d..1e3b808 100644 --- a/src/FLAD/screens/ProfilScreen.tsx +++ b/src/FLAD/screens/ProfilScreen.tsx @@ -5,15 +5,17 @@ import { Svg, Path } from 'react-native-svg'; import Modal from "react-native-modal"; import { useNavigation } from "@react-navigation/native"; import { useDispatch, useSelector } from 'react-redux'; +import * as AuthSession from 'expo-auth-session'; import normalize from '../components/Normalize'; import * as ImagePicker from 'expo-image-picker'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { colorsDark } from '../constants/colorsDark'; import { colorsLight } from '../constants/colorsLight'; import { deleteUser } from '../redux/thunk/authThunk'; -import { setImage, setMail, setName, setPassword } from '../redux/thunk/userThunk'; +import { setImage, setMail, setName, setPassword, setSpotify } from '../redux/thunk/userThunk'; import { setErrorUpdate } from '../redux/actions/userActions'; import * as FileSystem from 'expo-file-system'; +import configs from '../constants/config'; // @ts-ignore const DismissKeyboard = ({ children }) => ( @@ -85,6 +87,31 @@ export default function ProfilScreen() { return `data:image/jpg;base64,${base64}`; }; + const submitSpotify = async () => { + const token = await getSpotifyToken(); + if (token !== undefined) { + //@ts-ignore + dispatch(setSpotify(token)); + } + }; + + const getSpotifyToken = async () => { + try { + const redirectUri = AuthSession.makeRedirectUri(); + const result: any = await AuthSession.startAsync({ + authUrl: configs.API_URL + '/spotify/exchange?' + 'redirectUrl=' + + encodeURIComponent(redirectUri) + }) + const { + refresh_token: refresh_token, + } = result.params + return refresh_token; + } catch (error) { + Alert.alert("Erreur modification", "La connexion à Spotify à échouer."); + return; + } + } + const submitUsername = () => { const isUsernameValid = /^\w+$/.test(username); @@ -250,7 +277,7 @@ export default function ProfilScreen() { backgroundColor: style.Card, borderRadius: 13, alignItems: 'flex-start', - marginBottom: normalize(45) + marginBottom: normalize(35) }, textOption: { fontSize: normalize(18), @@ -271,6 +298,11 @@ export default function ProfilScreen() { color: '#1c77fb', marginLeft: 12 }, + textOptionSpotify: { + fontSize: normalize(18), + color: '#1DB954', + marginLeft: 12 + }, buttonDeleteOption: { backgroundColor: '#DF0404', padding: 5, @@ -309,6 +341,14 @@ export default function ProfilScreen() { fontSize: normalize(18) }, passwordOption: { + paddingVertical: 9, + paddingLeft: normalize(10), + backgroundColor: style.Card, + borderRadius: 13, + alignItems: 'flex-start', + marginBottom: normalize(30) + }, + spotifyOption: { paddingVertical: 9, paddingLeft: normalize(10), backgroundColor: style.Card, @@ -316,6 +356,13 @@ export default function ProfilScreen() { alignItems: 'flex-start', marginBottom: normalize(45) }, + spotifyView: { + backgroundColor: '#1DB954', + padding: 5, + paddingHorizontal: 5, + borderRadius: 10, + marginLeft: 10 + }, passwordIcon: { backgroundColor: '#8e8d92', padding: 5, @@ -323,6 +370,10 @@ export default function ProfilScreen() { borderRadius: 10, marginLeft: 10 }, + spotifyIcon: { + width: 20, + height: 20 + }, optionView: { flexDirection: 'row', marginTop: 5 @@ -425,7 +476,7 @@ export default function ProfilScreen() { {username.length >= 5 && ( - submitUsername()}> + )} @@ -435,7 +486,7 @@ export default function ProfilScreen() { {email.length >= 7 && ( - submitEmail()}> + )} @@ -455,13 +506,24 @@ export default function ProfilScreen() { + + + + + + + Changer de compte Spotify + + + + - deleteAccount()}> + Supprimer le compte @@ -476,7 +538,7 @@ export default function ProfilScreen() { Mot de passe submitPassword()}> + onPress={submitPassword}> = 6 && newPassword === confirmPassword && oldPassword.length >= 6 ? '#1c77fb' : '#404040', diff --git a/src/FLAD/screens/RegisterScreen.tsx b/src/FLAD/screens/RegisterScreen.tsx index feb86e8..8dc64a5 100644 --- a/src/FLAD/screens/RegisterScreen.tsx +++ b/src/FLAD/screens/RegisterScreen.tsx @@ -89,7 +89,6 @@ export default function RegisterScreen() { encodeURIComponent(redirectUri) }) const { - access_token: access_token, refresh_token: refresh_token, } = result.params setSpotifyToken(refresh_token) @@ -99,7 +98,6 @@ export default function RegisterScreen() { } } - return ( diff --git a/src/FLAD/screens/SpotScreen.tsx b/src/FLAD/screens/SpotScreen.tsx index 6fa7576..c48c7ce 100644 --- a/src/FLAD/screens/SpotScreen.tsx +++ b/src/FLAD/screens/SpotScreen.tsx @@ -90,11 +90,12 @@ export default function SpotScreen() { }, header: { left: width / 11, - top: '2.5%', + top: '2.2%', }, titleLabel: { fontStyle: 'normal', color: "#FFFFFF", + marginTop: 2, fontSize: normalize(40), fontWeight: "800", },