Update API and can change spotify account

pull/19/head
Emre KARTAL 1 year ago
parent 85b47bf961
commit a0f7cbf89c

@ -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:**
<br>
: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 !
<br>
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:**
<br>
: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 :
<div align = center>
@ -102,7 +100,7 @@ Tout d'abord, il faut fournir votre *adresse e-mail* et votre *nom Spotify* aux
</div>
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:.
<br/>
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.
<br/>
`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.
<br/>
### Voici un petit récapitulatif
<div align="center">
<table>
@ -125,9 +128,9 @@ Dans la page **settings** ⚙️, vous avez accès à toutes vos informations ``
<td align="center"><img src="doc/Images/Like_Img.png" alt="Button 3" width="100" height="100"></td>
</tr>
<tr>
<td align="center">Suprimer de la pile un spot</td>
<td align="center">Ajout 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)</td>
<td align="center">Like pour ajouter au favorie</td>
<td align="center">Supprimer de la pile un spot</td>
<td align="center">Ajout dans une playlist de votre compte Spotify (créée spécialement par l'application)</td>
<td align="center">Ajouter à vos favoris</td>
</tr>
</table>
</div>

@ -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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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);
}
};
}

@ -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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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<Response | void> => {
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)
}
}
}

@ -129,6 +129,21 @@ class UserService {
}
}
public async setSpotify(userId: string, tokenSpotify: string, idSpotify: string, image: string): Promise<void | Error> {
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<void | Error> {
try {
await this.user.findByIdAndUpdate(

@ -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: {

@ -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"
},

@ -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é !"));

@ -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
@ -120,3 +121,38 @@ 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;
}
}
}
}

@ -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";

@ -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() {
<TextInput placeholderTextColor='#828288' value={username}
onChangeText={setUsername} placeholder={userCurrent.name} style={styles.textInputId} />
{username.length >= 5 && (
<TouchableOpacity onPress={() => submitUsername()}>
<TouchableOpacity onPress={submitUsername}>
<Image source={require("../assets/images/confirm_icon.png")} style={{ width: normalize(25), height: normalize(25) }} />
</TouchableOpacity>
)}
@ -435,7 +486,7 @@ export default function ProfilScreen() {
<TextInput placeholderTextColor='#828288' value={email}
onChangeText={setEmail} placeholder={userCurrent.email} style={styles.textInputMail} />
{email.length >= 7 && (
<TouchableOpacity onPress={() => submitEmail()}>
<TouchableOpacity onPress={submitEmail}>
<Image source={require("../assets/images/confirm_icon.png")} style={{ width: normalize(25), height: normalize(25) }} />
</TouchableOpacity>
)}
@ -455,13 +506,24 @@ export default function ProfilScreen() {
</TouchableOpacity>
</View>
<View style={styles.spotifyOption}>
<TouchableOpacity style={{ flexDirection: 'row' }} onPress={submitSpotify}>
<View style={styles.spotifyView}>
<Image style={styles.spotifyIcon} source={require("../assets/images/spotify_icon.png")} />
</View>
<View style={styles.optionView}>
<Text style={styles.textOptionSpotify}>Changer de compte Spotify</Text>
</View>
</TouchableOpacity>
</View>
<View style={styles.deleteOption}>
<View style={styles.buttonDeleteOption}>
<Svg width="20" height="20" viewBox="0 0 29 29">
<Path d="M10.8157 22.6797C10.3586 22.6797 10.0657 22.4101 10.0422 21.9648L9.69067 9.0625C9.67895 8.62891 9.97192 8.34765 10.4407 8.34765C10.8743 8.34765 11.179 8.61719 11.1907 9.05078L11.5657 21.9648C11.5774 22.3984 11.2727 22.6797 10.8157 22.6797ZM14.3899 22.6797C13.9328 22.6797 13.6164 22.3984 13.6164 21.9648V9.0625C13.6164 8.62891 13.9328 8.34765 14.3899 8.34765C14.8469 8.34765 15.175 8.62891 15.175 9.0625V21.9648C15.175 22.3984 14.8469 22.6797 14.3899 22.6797ZM17.9758 22.6797C17.5188 22.6797 17.2141 22.3984 17.2258 21.9648L17.5891 9.0625C17.6008 8.61719 17.9055 8.34765 18.3391 8.34765C18.8078 8.34765 19.1008 8.62891 19.0891 9.0625L18.7375 21.9648C18.7141 22.4101 18.4211 22.6797 17.9758 22.6797ZM9.24536 5.5H11.1086V2.99219C11.1086 2.32422 11.5774 1.89062 12.2805 1.89062H16.4758C17.1789 1.89062 17.6477 2.32422 17.6477 2.99219V5.5H19.5109V2.875C19.5109 1.17578 18.4094 0.144531 16.6047 0.144531H12.1516C10.3469 0.144531 9.24536 1.17578 9.24536 2.875V5.5ZM3.92505 6.4375H24.8664C25.3469 6.4375 25.7336 6.02734 25.7336 5.54687C25.7336 5.06641 25.3469 4.66797 24.8664 4.66797H3.92505C3.4563 4.66797 3.04614 5.06641 3.04614 5.54687C3.04614 6.03906 3.4563 6.4375 3.92505 6.4375ZM9.0227 26.2422H19.7688C21.4445 26.2422 22.5695 25.1523 22.6516 23.4765L23.4719 6.19141H5.30786L6.13989 23.4883C6.22192 25.164 7.32348 26.2422 9.0227 26.2422Z" fill="white" fill-opacity="0.85" />
</Svg>
</View>
<TouchableOpacity onPress={() => deleteAccount()}>
<TouchableOpacity onPress={deleteAccount}>
<Text style={styles.textDeleteOption}>Supprimer le compte</Text>
</TouchableOpacity>
</View>
@ -476,7 +538,7 @@ export default function ProfilScreen() {
<Text style={styles.titlePassword}>Mot de passe</Text>
<TouchableOpacity
disabled={newPassword.length < 6 || newPassword !== confirmPassword || oldPassword.length < 6}
onPress={() => submitPassword()}>
onPress={submitPassword}>
<View>
<Text style={[styles.updateText, {
color: newPassword.length >= 6 && newPassword === confirmPassword && oldPassword.length >= 6 ? '#1c77fb' : '#404040',

@ -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 (
<DismissKeyboard>
<View style={styles.container}>

@ -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",
},

Loading…
Cancel
Save