From 464933ef6868fd3fbd15ef0c540553190b2b0683 Mon Sep 17 00:00:00 2001 From: dadalmeida1 Date: Tue, 21 Feb 2023 22:02:28 +0100 Subject: [PATCH] Mongo database almost done --- src/Api/package.json | 5 + src/Api/src/app.ts | 12 +- .../spotify-controller/spotifyCtrl.ts | 130 +++----- .../controller/user-controller/userCtrl.ts | 279 +++++++++++------- src/Api/src/database/MongoDataBase.ts | 5 +- src/Api/src/database/schema/LocationSchema.ts | 36 +++ .../src/database/schema/NotificationSchema.ts | 6 +- src/Api/src/database/schema/Token/IToken.ts | 8 + .../src/database/schema/User/UserInterface.ts | 11 + .../src/database/schema/User/UserSchema.ts | 79 +++++ .../database/schema/User/UserValidation.ts | 18 ++ src/Api/src/database/schema/UserSchema.ts | 21 -- src/Api/src/middleware/authMiddleware.ts | 45 +++ .../validation/ValidatorMiddleware.ts | 33 +++ src/Api/src/model/token.ts | 27 ++ src/Api/src/server.ts | 3 +- src/Api/src/service/LocationService.ts | 51 ++-- src/Api/src/service/UserService.ts | 63 ++++ src/FLAD/App.tsx | 36 ++- src/FLAD/Model/Music.tsx | 3 +- src/FLAD/Model/Spot.tsx | 3 +- src/FLAD/Model/User.tsx | 2 +- src/FLAD/assets/icons/light_like.riv | Bin 7522 -> 0 bytes src/FLAD/assets/icons/splash.png | Bin 16002 -> 51768 bytes src/FLAD/assets/icons/splashs.png | Bin 0 -> 16002 bytes src/FLAD/components/Card.tsx | 37 +-- src/FLAD/components/button/button.tsx | 2 +- src/FLAD/data/data.ts | 22 +- src/FLAD/navigation/Navigation.tsx | 5 +- src/FLAD/package.json | 8 +- src/FLAD/screens/favoritePage.tsx | 2 +- src/FLAD/screens/login.tsx | 2 +- src/FLAD/screens/spot.tsx | 106 ++++--- 33 files changed, 705 insertions(+), 355 deletions(-) create mode 100644 src/Api/src/database/schema/LocationSchema.ts create mode 100644 src/Api/src/database/schema/Token/IToken.ts create mode 100644 src/Api/src/database/schema/User/UserInterface.ts create mode 100644 src/Api/src/database/schema/User/UserSchema.ts create mode 100644 src/Api/src/database/schema/User/UserValidation.ts delete mode 100644 src/Api/src/database/schema/UserSchema.ts create mode 100644 src/Api/src/middleware/authMiddleware.ts create mode 100644 src/Api/src/middleware/validation/ValidatorMiddleware.ts create mode 100644 src/Api/src/model/token.ts delete mode 100644 src/FLAD/assets/icons/light_like.riv create mode 100644 src/FLAD/assets/icons/splashs.png diff --git a/src/Api/package.json b/src/Api/package.json index f2cf2e8..2769247 100644 --- a/src/Api/package.json +++ b/src/Api/package.json @@ -11,9 +11,11 @@ "author": "", "license": "ISC", "devDependencies": { + "@types/bcrypt": "^5.0.0", "@types/cors": "^2.8.13", "@types/debug": "^4.1.7", "@types/express": "^4.17.16", + "@types/jsonwebtoken": "^9.0.1", "@types/morgan": "^1.9.4", "nodemon": "^2.0.20", "ts-node": "^10.9.1", @@ -24,8 +26,11 @@ "@types/mongoose": "^5.11.97", "@types/request": "^2.48.8", "axios": "^1.2.6", + "bcrypt": "^5.1.0", "cors": "^2.8.5", "express-winston": "^4.2.0", + "joi": "^17.8.1", + "jsonwebtoken": "^9.0.0", "mongodb": "^5.0.0", "mongoose": "^6.9.0", "morgan": "^1.10.0", diff --git a/src/Api/src/app.ts b/src/Api/src/app.ts index dd14310..d3f8d36 100644 --- a/src/Api/src/app.ts +++ b/src/Api/src/app.ts @@ -6,6 +6,7 @@ import cors from 'cors'; import Controller from './controller/Icontroller'; // import ErrorMiddleware from './middleware/error.middleware'; import bodyParser from 'body-parser'; +import mongoose from 'mongoose'; // to secure // import helmet from 'helmet'; @@ -24,7 +25,7 @@ class App { this.port = port; this.dataBase = null; - // this.initialiseDatabase(); + this.initialiseDatabase(); this.initialiseMiddleware(); this.initialiseControllers(controllers); @@ -61,7 +62,14 @@ class App { console.log(`⚡️[server] : App listening on the port ${this.port}`); }); } - + + private initialiseDatabase(): void { + const { MONGO_USER, MONGO_PASSWORD, MONGO_PATH } = process.env; + const uri = "mongodb+srv://fladDevDb:ZslYlNRWIOUU7i6o@fladcluster.b29tytu.mongodb.net/?retryWrites=true&w=majority" + mongoose.connect(uri) + .then(() => console.log("Connect to MongoDB database successfully")) + .catch(err => console.log("Error connecting : "+ err )); + } } diff --git a/src/Api/src/controller/spotify-controller/spotifyCtrl.ts b/src/Api/src/controller/spotify-controller/spotifyCtrl.ts index b826ee0..a26f33b 100644 --- a/src/Api/src/controller/spotify-controller/spotifyCtrl.ts +++ b/src/Api/src/controller/spotify-controller/spotifyCtrl.ts @@ -23,6 +23,8 @@ class SpotifyController implements Controller { this.router.get(`${this.path}/callback`,this.getAccessToken); // this.router.post(`${this.path}/refresh`,this.getRefreshToken); this.router.get(`${this.path}/play/:musicId`, this.getMusic); + this.router.get(`${this.path}/spot`, this.getSpot); + } // need to put in ENvironement file @@ -134,85 +136,49 @@ class SpotifyController implements Controller { } } - // }; - + public getMusic(){ return null; } - // private spotifyRequest = (params : AuthReqBody) => { - // return new Promise(() => { - // console.log("============ on est laaaa sa mer"); - // var code = req.query.code || null; - // var state = req.query.state || null; + public getSpot = async ( + req: Request, + res: Response, + next: NextFunction + ): Promise => { + const spots = [ + { + name: "blue", + sourceUrl: "https://cdns-images.dzcdn.net/images/artist/399e7e760d8fedf3cc2891e9c0c41658/200x200-000000-80-0-0.jpg", + index: 3 + }, + { + name: "strange history", + sourceUrl: "https://images.genius.com/339dfe2a7c0adf9a5d08febf29a845f4.1000x1000x1.jpg", + index: 7 + }, + { + name: "oboy album", + sourceUrl: "https://i.pinimg.com/originals/ad/cc/d5/adccd58a0d0ff516a6114703cd05810e.jpg", + index: 1 + } + ]; + try { + res.send(spots); + + } catch (error) { + console.log('heuuuuuuuuuuuuuuuuuuuuubizzzaaarrreeee'); + console.log(error); + next(new HttpException(400, 'On peut pas avoir darray mec')); + } } - // axios.post(this.API_URL, { - // form: params, - // headers: { - // "Authorization": "Basic " + new Buffer(this.CLIENT_ID + ":" + this.CLIENT_SECRET).toString('base64') - // }, - // json: true - // }); - // }).then(resp => { - // if (resp.statusCode != 200) { - // return Promise.reject({ - // statusCode: resp.statusCode, - // body: resp.body - // }); - // } - // return Promise.resolve(resp.body); - // }) - // .catch(err => { - // return Promise.reject({ - // statusCode: 500, - // body: err.stringify({}) - // }); - // }); - // }; private getAccessToken = async ( req: Request, res: Response, next: NextFunction ): Promise => { - - // console.log("heheh"); - // try { - // var code = req.query.code; - // var state = req.query.state; - // console.log("================================================================================================================================"); - // console.log(req); - // console.log("================================================================================================================================"); - - // if (state === null) { - // next(new HttpException(400, 'Cannot create twerk')); - // } else { - // const resp : any = await axios.post('https://accounts.spotify.com/api/token',{ - // form: { - // code: code, - // redirect_uri: this.CALLBACK_URL, - // // code_verifier : this.ENCRYPTION_SECRET.stringCrypt, - // grant_type: 'authorization_code' - // }, - // headers: { - // 'Authorization': 'Basic ' + (new Buffer(this.CLIENT_ID + ':' + this.CLIENT_SECRET).toString('base64')), - // },json: true} - // ); - // if (resp.statusCode != 200) { - // console.log(resp.statusCode, resp.body); - // } - // else{ - // console.log("error"); - // console.log(resp.statusCode, resp.body); - // } - - // } - // // }); - // } catch (error) { - // console.log(error); - // next(new HttpException(400, 'Cannot create spot')); - // } var code = req.query.code; var state = req.query.state || null; @@ -249,39 +215,9 @@ class SpotifyController implements Controller { } - // axios({ - // method: 'post', - // url: 'https://accounts.spotify.com/api/token', - // data: { - // firstName: 'Fred', - // lastName: 'Flintstone' - // }, - // headers: { - // 'Authorization': 'Basic ' + ( Buffer.from(this.CLIENT_ID + ':' + this.CLIENT_SECRET).toString('base64')), - // 'Content-Type' : 'application/x-www-form-urlencoded' - // }, - // }); - // request.post(authOptions, function(error, response, body) { - // if (!error && response.statusCode === 200) { - // var access_token = body.access_token; - // console.log(access_token); - // res.redirect(200, '/') - // } - // console.log(error); - // }); }; - - private encrypt(text :any){ - return CryptoJS.AES.encrypt(text, this.ENCRYPTION_SECRET.stringCrypt).toString(); - }; - - private decrypt(text: any) { - console.log("errer"); - var bytes = CryptoJS.AES.decrypt(text, this.ENCRYPTION_SECRET.stringCrypt); - return bytes.toString(CryptoJS.enc.Utf8); - }; } export default SpotifyController; diff --git a/src/Api/src/controller/user-controller/userCtrl.ts b/src/Api/src/controller/user-controller/userCtrl.ts index f7f5bc8..004e20e 100644 --- a/src/Api/src/controller/user-controller/userCtrl.ts +++ b/src/Api/src/controller/user-controller/userCtrl.ts @@ -1,11 +1,15 @@ import { Router, Request, Response, NextFunction, RequestHandler } from 'express'; import Controller from '../Icontroller'; import HttpException from '../../middleware/exeption/httpExeption'; +// import LocationService from '../../service/LocationService'; +import IUser from '../../database/schema/User/UserInterface'; +import UserService from '../../service/UserService'; +import validator from '../../database/schema/User/UserValidation' +import validationMiddleware from '../../middleware/validation/ValidatorMiddleware'; +import authenticator from '../../middleware/authMiddleware' import LocationService from '../../service/LocationService'; - - -class TaskController implements Controller { - public path = '/task'; +class UserController implements Controller { + public path = '/users'; public router = Router(); private userService = new UserService(); private locationService = new LocationService(); @@ -15,131 +19,193 @@ class TaskController implements Controller { } private initialiseRoutes(): void { - //create - this.router.post(`${this.path}`,this.createUser); - - // // get One - this.router.get (`${this.path}/:userId`, this.getUserById); - // // get All - this.router.get (`${this.path}`, this.getAllUsers); + this.router.post( + `${this.path}/register`, + validationMiddleware(validator.register), + this.register + ); + this.router.post( + `${this.path}/login`, + validationMiddleware(validator.login), + this.login + ); + this.router.get(`${this.path}`, authenticator, this.getUser); + this.router.get(`${this.path}/nextTo`, authenticator, this.getUserNext); - //update One - this.router.put (`${this.path}/:userId`, this.updateUser); - //Delete One - this.router.delete (`${this.path}/:userId`, this.deleteUser); + // //create + // this.router.post(`${this.path}`,this.createUser); + + // // // get One + // this.router.get (`${this.path}/:userId`, this.getUserById); + // // // get All + // this.router.get (`${this.path}`, this.getAllUsers); + // //update One + // this.router.put (`${this.path}/:userId`, this.updateUser); + // //Delete One + // this.router.delete (`${this.path}/:userId`, this.deleteUser); } - private createUser = async ( - req: Request, - res: Response, - next: NextFunction - ): Promise => { - try { + // private createUser = async ( + // req: Request, + // res: Response, + // next: NextFunction + // ): Promise => { + // try { - console.log(req.body); - const reqBody:CreateTaskReqBody = Object.assign({}, req.body); - checkIfIsValidCreateTaskReqBody(reqBody); - await this.userService.createUserById(reqBody.fin - ); + // console.log(req.body); + // const reqBody:CreateTaskReqBody = Object.assign({}, req.body); + // checkIfIsValidCreateTaskReqBody(reqBody); + // await this.userService.createUserById(reqBody.fin + // ); - res.status(200).send({ status: "Success", msg: "Success add" }); + // res.status(200).send({ status: "Success", msg: "Success add" }); - } catch (error) { - next(new HttpException(400, 'Cannot create post')); - } - }; - private readonly getUserById: RequestHandler = async ( - req: Request, - res: Response, - next: NextFunction - ): Promise => { - try { - const id = req.params.taskId; - const userId = req.params.userId; + // } catch (error) { + // next(new HttpException(400, 'Cannot create post')); + // } + // }; + // private readonly getUserById: RequestHandler = async ( + // req: Request, + // res: Response, + // next: NextFunction + // ): Promise => { + // try { + // const id = req.params.taskId; + // const userId = req.params.userId; - const data = await this.userService.getUserById(id, userId); - res.status(201).send(data); + // const data = await this.userService.getUserById(id, userId); + // res.status(201).send(data); - } - catch(error){ - next(new HttpException(400, 'Cannot create post')); - } + // } + // catch(error){ + // next(new HttpException(400, 'Cannot create post')); + // } - } - private readonly getAllUsers: RequestHandler = async ( + // } + // private readonly getAllUsers: RequestHandler = async ( + // req: Request, + // res: Response, + // next: NextFunction + // ): Promise => { + // try { + // const userId = req.params.userId; + // const tasks = await this.userService.getUsers(userId); + // const responseList = tasks.map(task => new TaskResumedRes(task)); + // res.status(201).send(responseList); + + // } + // catch(error){ + // next(new HttpException(400, 'Cannot get user task')); + // } + + // } + + // private deleteUser = async ( + // req: Request, + // res: Response, + // next: NextFunction + // ): Promise => { + // try { + // const id = req.params.taskId; + // const userId = req.params.userId; + // await this.userService.DeleteUser(id, userId); + // return res.status(200).send({ status: "Success", msg: "Data Removed" }); + // } catch (error) { + // next(new HttpException(400, 'Cannot create post')); + // } + // }; + + // private updateUser = async ( + // req: Request, + // res: Response, + // next: NextFunction + // ): Promise => { + // try { + + // const taskId = req.params.taskId; + // const userId = req.params.userId; + // const reqBody:CreateTaskReqBody = Object.assign({}, req.body); + + // const updatedTask = await this.userService.UpdateTask( + // // req.auth!.uid, + // taskId, + // userId, + // // firebase.auth().currentUser.getIdToken() + // reqBody.nom, + // reqBody.description, + // reqBody.logo, + // reqBody.duration, + // reqBody.done, + // // reqBody.tags, + // reqBody.repepat, + // reqBody.deb, + // reqBody.fin + // ); + // // res.send('Success add'); + // // res.status(201).json({ task }); + // res.status(204).send(`Update a new contact: ${updatedTask}`); + // } catch (error) { + // console.log(error); + // next(new HttpException(403, 'Cannot create post')); + // } + // }; + + + private register = async ( req: Request, res: Response, next: NextFunction ): Promise => { try { - const userId = req.params.userId; - const tasks = await this.userService.getUsers(userId); - const responseList = tasks.map(task => new TaskResumedRes(task)); - res.status(201).send(responseList); + // the FladId should be created by the Userservice + const { name, email, password,idFlad, idSpotify } = req.body; + const token = await this.userService.register( + name, + email, + password, + idFlad, + idSpotify + ); + + res.status(201).json({ token }); + } catch (error : any) { + next(new HttpException(400, error.message)); } - catch(error){ - next(new HttpException(400, 'Cannot get user task')); - } - - } - - private deleteUser = async ( + }; + + private login = async ( req: Request, res: Response, next: NextFunction ): Promise => { try { - const id = req.params.taskId; - const userId = req.params.userId; - await this.userService.DeleteUser(id, userId); - return res.status(200).send({ status: "Success", msg: "Data Removed" }); - } catch (error) { - next(new HttpException(400, 'Cannot create post')); + 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)); } }; - - private updateUser = async ( + + private getUser = ( req: Request, res: Response, next: NextFunction - ): Promise => { - try { - - const taskId = req.params.taskId; - const userId = req.params.userId; - const reqBody:CreateTaskReqBody = Object.assign({}, req.body); - - const updatedTask = await this.userService.UpdateTask( - // req.auth!.uid, - taskId, - userId, - // firebase.auth().currentUser.getIdToken() - reqBody.nom, - reqBody.description, - reqBody.logo, - reqBody.duration, - reqBody.done, - // reqBody.tags, - reqBody.repepat, - reqBody.deb, - reqBody.fin - ); - // res.send('Success add'); - // res.status(201).json({ task }); - res.status(204).send(`Update a new contact: ${updatedTask}`); - } catch (error) { - console.log(error); - next(new HttpException(403, 'Cannot create post')); + ): Response | void => { + if (!req.user) { + return next(new HttpException(404, 'No logged in user')); } + + res.status(200).send({ data: req.user }); }; - - - private getUserNext: RequestHandler = async ( + private getUserNext = async ( req: Request, res: Response, next: NextFunction @@ -152,18 +218,29 @@ class TaskController implements Controller { console.log('Impossible de convertir la chaîne en nombre'); } //} - const userId = req.body.userId; + const userId = req.user.idFlad; const data = await this.locationService.getNearUser(userId,latitude,longitude); console.log(data); res.status(201).send(data); } - catch(error){ - next(new HttpException(400, 'Cannot create post')); + catch(error : any){ + next(new HttpException(400, 'Cannot create get netUser')); } } + } -export default TaskController; \ No newline at end of file +export default UserController; + + + +declare global { + namespace Express { + export interface Request { + user: IUser; + } + } +} \ No newline at end of file diff --git a/src/Api/src/database/MongoDataBase.ts b/src/Api/src/database/MongoDataBase.ts index 1e9bd7d..dd8f5d3 100644 --- a/src/Api/src/database/MongoDataBase.ts +++ b/src/Api/src/database/MongoDataBase.ts @@ -1,3 +1,4 @@ -const uri = "mongodb+srv://fladDevDb:ZslYlNRWIOUU7i6o@fladcluster.b29tytu.mongodb.net/?retryWrites=true&w=majority" -export default db = new MongoClient(uri); \ No newline at end of file +// export default db = new MongoClient(uri); + + diff --git a/src/Api/src/database/schema/LocationSchema.ts b/src/Api/src/database/schema/LocationSchema.ts new file mode 100644 index 0000000..795d45f --- /dev/null +++ b/src/Api/src/database/schema/LocationSchema.ts @@ -0,0 +1,36 @@ +import { Schema, model } from 'mongoose'; + + +const locationSchema = new Schema( + { + + idFlad: { + type: String, + required: true, + unique: true, + }, + + latitude: { + type: Number, + required: true, + }, + longitude: { + type: Number, + required: true, + }, + + + }, + { timestamps: true } +); + +// fladDevDb +// ZslYlNRWIOUU7i6o +export default model('Location', locationSchema); + +export interface ILocation extends Document { + idFlad: string; + latitude : number; + longitude: number; + +} \ No newline at end of file diff --git a/src/Api/src/database/schema/NotificationSchema.ts b/src/Api/src/database/schema/NotificationSchema.ts index 7aa9525..7207503 100644 --- a/src/Api/src/database/schema/NotificationSchema.ts +++ b/src/Api/src/database/schema/NotificationSchema.ts @@ -1,6 +1,8 @@ -const notificationSchema = new mongoose.Schema({ +import { Schema, model } from 'mongoose'; + +const notificationSchema = new Schema({ type: {type: String, required: true}, content: {type: String, required: true} }); -export default {Annonce: mongoose.model("nofitication", notificationSchema)} \ No newline at end of file +export default {Notification: model("nofitication", notificationSchema)} \ No newline at end of file diff --git a/src/Api/src/database/schema/Token/IToken.ts b/src/Api/src/database/schema/Token/IToken.ts new file mode 100644 index 0000000..ff6e4af --- /dev/null +++ b/src/Api/src/database/schema/Token/IToken.ts @@ -0,0 +1,8 @@ +import { Schema } from 'mongoose'; + +interface IToken extends Object { + id: Schema.Types.ObjectId; + expiresIn: number; +} + +export default IToken; \ No newline at end of file diff --git a/src/Api/src/database/schema/User/UserInterface.ts b/src/Api/src/database/schema/User/UserInterface.ts new file mode 100644 index 0000000..2308f88 --- /dev/null +++ b/src/Api/src/database/schema/User/UserInterface.ts @@ -0,0 +1,11 @@ +import { Document } from 'mongoose'; + +export default interface IUser extends Document { + email: string; + name: string; + password: string; + idFlad : string; + idSpotify : string; + + isValidPassword(password: string): Promise; +} \ No newline at end of file diff --git a/src/Api/src/database/schema/User/UserSchema.ts b/src/Api/src/database/schema/User/UserSchema.ts new file mode 100644 index 0000000..8f8cdd5 --- /dev/null +++ b/src/Api/src/database/schema/User/UserSchema.ts @@ -0,0 +1,79 @@ +// maye this file should me the UserModel like we had in php cause it's here we verrify the password +import IUser from "./UserInterface"; +import { Schema, model } from 'mongoose'; +import bcrypt from 'bcrypt'; +// const userSchema: Schema = new Schema({ +// pseudo: {type: String, index: { unique: true }}, +// email: {type: String}, +// idDafl: {type: String, index: { unique: true }}, +// idSpotify: {type: String}, +// password: {type: String}, +// prenom: {type: String, default: ""}, +// description: {type: String, default: ""}, +// nom: {type: String, default: ""}, +// ville: {type: String, default: ""}, +// profilPic: {type: String}, +// noteList: [], +// notifications: [], +// friends: {type: [String] }, +// favoris: [], +// conversations: {type: [String] } +// }); + +const userSchema = new Schema( + { + + idFlad: { + type: String, + required: true, + unique: true, + }, + idSpotify: { + type: String, + required: true, + unique: true, + }, + name: { + type: String, + required: true, + }, + email: { + type: String, + required: true, + // this mean that we identify user by email + unique: true, + // delete the whitespace + trim: true, + }, + password: { + type: String, + }, + + }, + { timestamps: true } +); + +// this means that we hash the user password before saving it to the database +userSchema.pre('save', async function (next) { + if (!this.isModified('password')) { + //just had that to be sure that the api still going + return next(); + } + + const hash = await bcrypt.hash(this.password, 8); + + this.password = hash; + + next(); +}); + +userSchema.methods.isValidPassword = async function ( + password: string +): Promise< boolean | Error> { + return await bcrypt.compare(password, this.password); +}; + +// fladDevDb +// ZslYlNRWIOUU7i6o +export default model('User', userSchema); +// export const User: Model = model('User', userSchema); diff --git a/src/Api/src/database/schema/User/UserValidation.ts b/src/Api/src/database/schema/User/UserValidation.ts new file mode 100644 index 0000000..ec48660 --- /dev/null +++ b/src/Api/src/database/schema/User/UserValidation.ts @@ -0,0 +1,18 @@ +import Joi from 'joi'; + +const register = Joi.object({ + name: Joi.string().max(30).required(), + + email: Joi.string().email().required(), + + password: Joi.string().min(6).required(), + // can add an field like confimPassword and cheked that the password is equal to the confirmPassword + +}); + +const login = Joi.object({ + email: Joi.string().email().required(), + password: Joi.string().required(), +}); + +export default { register, login }; \ No newline at end of file diff --git a/src/Api/src/database/schema/UserSchema.ts b/src/Api/src/database/schema/UserSchema.ts deleted file mode 100644 index 27153b8..0000000 --- a/src/Api/src/database/schema/UserSchema.ts +++ /dev/null @@ -1,21 +0,0 @@ - -const userSchema: Schema = new mongoose.Schema({ - pseudo: {type: String, index: { unique: true }}, - email: {type: String}, - idDafl: {type: String, index: { unique: true }}, - idSpotify: {type: String}, - password: {type: String}, - prenom: {type: String, default: ""}, - description: {type: String, default: ""}, - nom: {type: String, default: ""}, - ville: {type: String, default: ""}, - profilPic: {type: String}, - noteList: [], - notifications: [], - friends: {type: [String] }, - favoris: [], - conversations: {type: [String] } -}); -// fladDevDb -// ZslYlNRWIOUU7i6o -export const User: Model = model('User', userSchema); diff --git a/src/Api/src/middleware/authMiddleware.ts b/src/Api/src/middleware/authMiddleware.ts new file mode 100644 index 0000000..bb0f875 --- /dev/null +++ b/src/Api/src/middleware/authMiddleware.ts @@ -0,0 +1,45 @@ +import { Request, Response, NextFunction } from 'express'; +import jwt from 'jsonwebtoken'; +import IToken from '../database/schema/Token/IToken'; +import UserSchema from '../database/schema/User/UserSchema'; +import token from '../model/token'; +import HttpException from './exeption/httpExeption'; + +async function authenticatedMiddleware( + req: Request, + res: Response, + next: NextFunction +): Promise { + const bearer = req.headers.authorization; + + if (!bearer || !bearer.startsWith('Bearer ')) { + return next(new HttpException(401, 'Unauthorised')); + } + + const accessToken = bearer.split('Bearer ')[1].trim(); + try { + const payload: IToken | jwt.JsonWebTokenError = await token.verifyToken( + accessToken + ); + + if (payload instanceof jwt.JsonWebTokenError) { + return next(new HttpException(401, 'Unauthorised')); + } + + const user = await UserSchema.findById(payload.id) + .select('-password') + .exec(); + + if (!user) { + return next(new HttpException(401, 'Unauthorised')); + } + + req.user = user; + + return next(); + } catch (error) { + return next(new HttpException(401, 'Unauthorised')); + } +} + +export default authenticatedMiddleware; \ No newline at end of file diff --git a/src/Api/src/middleware/validation/ValidatorMiddleware.ts b/src/Api/src/middleware/validation/ValidatorMiddleware.ts new file mode 100644 index 0000000..51e58f9 --- /dev/null +++ b/src/Api/src/middleware/validation/ValidatorMiddleware.ts @@ -0,0 +1,33 @@ +import { Request, Response, NextFunction, RequestHandler } from 'express'; +import Joi from 'joi'; + +function validationMiddleware(schema: Joi.Schema): RequestHandler { + return async ( + req: Request, + res: Response, + next: NextFunction + ): Promise => { + const validationOptions = { + abortEarly: false, + allowUnknown: true, + stripUnknown: true, + }; + + try { + const value = await schema.validateAsync( + req.body, + validationOptions + ); + req.body = value; + next(); + } catch (e: any) { + const errors: string[] = []; + e.details.forEach((error: Joi.ValidationErrorItem) => { + errors.push(error.message); + }); + res.status(400).send({ errors: errors }); + } + }; +} + +export default validationMiddleware; \ No newline at end of file diff --git a/src/Api/src/model/token.ts b/src/Api/src/model/token.ts new file mode 100644 index 0000000..ebc6f65 --- /dev/null +++ b/src/Api/src/model/token.ts @@ -0,0 +1,27 @@ +import jwt from 'jsonwebtoken'; +import IUser from '../database/schema/User/UserInterface'; +import IToken from '../database/schema/Token/IToken'; + +export const createToken = (user: IUser): string => { + return jwt.sign({ id: user._id }, "foo" as jwt.Secret, { + expiresIn: '100d', + }); +}; + +export const verifyToken = async ( + token: string +): Promise => { + return new Promise((resolve, reject) => { + jwt.verify( + token, + "foo" as jwt.Secret, + (err, payload) => { + if (err) return reject(err); + + resolve(payload as IToken); + } + ); + }); +}; + +export default { createToken, verifyToken }; \ No newline at end of file diff --git a/src/Api/src/server.ts b/src/Api/src/server.ts index 87e362b..1b3e87b 100644 --- a/src/Api/src/server.ts +++ b/src/Api/src/server.ts @@ -1,9 +1,10 @@ import App from "./app"; import SpotifyController from "./controller/spotify-controller/spotifyCtrl"; import PingController from "./controller/TestCtrl"; +import UserController from "./controller/user-controller/userCtrl"; const app = new App( - [new PingController(), new SpotifyController()], + [new PingController(), new SpotifyController(), new UserController()], Number(8080) // Number(process.env.PORT) diff --git a/src/Api/src/service/LocationService.ts b/src/Api/src/service/LocationService.ts index dd12d59..077c0a5 100644 --- a/src/Api/src/service/LocationService.ts +++ b/src/Api/src/service/LocationService.ts @@ -1,45 +1,48 @@ // import db from '../database'; import { Place, PlacePosition, Position, UserLocation } from '../model/locationModel'; import axios from 'axios'; +import LocationSchema from "../database/schema/LocationSchema"; class LocationService { - private API_KEY : string = "AIzaSyBFCEAtmhZ8jvw84UTQvX3Aqpr66GVqB_A"; - public async getNearUser(uuid : string, latitude : number, longitude : number) + private locationCollection = LocationSchema; + // private API_KEY : string = "AIzaSyBFCEAtmhZ8jvw84UTQvX3Aqpr66GVqB_A"; + public async getNearUser(idFlad : string, latitude : number, longitude : number) { - const UserCollectionref = db.collection('UserPosition'); - db.collection('UserPosition').doc(uuid).set({uuid : uuid, latitude : latitude, longitude : longitude}); - // const newPosition = { - // name: 'Los Angeles', - // state: 'CA', - // country: 'USA' - // }; - const snapshot = await UserCollectionref.where("uuid", "!=", uuid).get(); - if (snapshot.empty) { - console.log('No matching documents.'); - return; - } + await this.locationCollection.findOneAndUpdate( + { idFlad }, + { idFlad, latitude, longitude }, + { upsert: true } + ); + + const snapshot = await this.locationCollection.find({ idFlad: { $ne: idFlad } }); + if (snapshot.length === 0) { + console.log('No matching documents.'); + return; + } let dbUsersList:UserLocation[] = []; snapshot.forEach(doc => { - dbUsersList.push(new UserLocation(doc.data().uuid,doc.data().latitude,doc.data().longitude)); - console.log(doc.id, '=>', doc.data()); + dbUsersList.push(new UserLocation(doc.idFlad,doc.latitude,doc.longitude)); + console.log(doc.idFlad, '=>', doc); }); - - let listUser: string[] = []; //Set the listUser to an empty list + // missing the curent music + let listUser: string[] = []; dbUsersList.forEach(user => { console.log(user); - const dist = this.distanceBetween(latitude , longitude , user.latitude, user.longitude); //With the function meters, determinate the distance between the current user and the user who is in the actual row + const dist = this.distanceBetween(latitude , longitude , user.latitude, user.longitude); console.log(user.uuid,dist); - if (dist <= 5) { //If the user in the actual row is less than 100 meters away of the current user + if (dist <= 100) { - listUser.push(user.uuid); //Add the username and the ID of the song that user who is in the actual row is listening + listUser.push(user.uuid); } - }); + }); + + - return listUser; //Return an array - // $listUser[] = ['user' => $userID, 'music' => $idMusic]; //Add the username and the ID of the song that user who is in the actual row is listening + return listUser; + // $listUser[] = {userID,idMusic}; } diff --git a/src/Api/src/service/UserService.ts b/src/Api/src/service/UserService.ts index e69de29..682a963 100644 --- a/src/Api/src/service/UserService.ts +++ b/src/Api/src/service/UserService.ts @@ -0,0 +1,63 @@ +import UserSchema from "../database/schema/User/UserSchema"; +import token from "../model/token"; + + +class UserService { + private user = UserSchema; + + /** + * Register a new user + */ + public async register( + name: string, + email: string, + password: string, + idFlad : string, + idSpotify : string + ): Promise { + try { + const user = await this.user.create({ + name, + email, + password, + idFlad, + idSpotify + }); + + const accessToken = token.createToken(user); + + return accessToken; + } catch (error : any) { + throw new Error(error.message); + } + } + + /** + * Attempt to login a user + */ + public async login( + email: string, + password: string + ): Promise { + try { + // should maybe creat a method base on id and other information for better security + // need to view with Emre + const user = await this.user.findOne({ email }); + // const user = await this.user.findById(idFlad); + + if (!user) { + throw new Error('Unable to find user with that email address'); + } + + if (await user.isValidPassword(password)) { + return token.createToken(user); + } else { + throw new Error('Wrong credentials given'); + } + } catch (error) { + throw new Error('Unable to create user'); + } + } +} + +export default UserService; \ No newline at end of file diff --git a/src/FLAD/App.tsx b/src/FLAD/App.tsx index 1a25a6d..9ac5ad2 100644 --- a/src/FLAD/App.tsx +++ b/src/FLAD/App.tsx @@ -8,20 +8,50 @@ import { NavigationContainer } from '@react-navigation/native'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { Animated, Dimensions, ImageBackground, StyleSheet, Text, View } from 'react-native'; import Card from './components/Card'; -import Login from './pages/login'; -import Spot from './pages/spot'; +// import Login from './screens/login'; +import Spot from './screens/spot'; +import StackNavigation from './navigation/Navigation'; export default function App() { const Stack = createBottomTabNavigator(); +const {width : wWidht} = Dimensions.get("window"); return ( - + + ); } +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center', + }, + card: { + borderRadius : 8, + shadowRadius : 20, + shadowColor : '#' + }, + image: { + width: 320, + height: 440, + borderRadius: 18, + resizeMode : "cover", + placeholder: "assets/images/loadingPlaceholder.gif" + }, + gradient : { + position : "absolute", + top : 0, + left : 0, + right : 0, + height : 209, + } +}); \ No newline at end of file diff --git a/src/FLAD/Model/Music.tsx b/src/FLAD/Model/Music.tsx index fe933c9..cc20984 100644 --- a/src/FLAD/Model/Music.tsx +++ b/src/FLAD/Model/Music.tsx @@ -1,4 +1,4 @@ -class Music { +export default class Music { private id : string; private name : string; private artist : string; @@ -10,4 +10,5 @@ class Music { this.artist = artist; this.linkCover = linkCover; } + } diff --git a/src/FLAD/Model/Spot.tsx b/src/FLAD/Model/Spot.tsx index 53d37d0..cc8fa6d 100644 --- a/src/FLAD/Model/Spot.tsx +++ b/src/FLAD/Model/Spot.tsx @@ -1,6 +1,7 @@ + class Spot { private userId : string; - public music : Music;; + public music : Music; constructor(userId : string, music : Music){ this.userId = userId; this.music = music; diff --git a/src/FLAD/Model/User.tsx b/src/FLAD/Model/User.tsx index 39fad6d..1e7f2bd 100644 --- a/src/FLAD/Model/User.tsx +++ b/src/FLAD/Model/User.tsx @@ -1,6 +1,6 @@ class User { //attributes from DAFL - private idDafl : any;; + private idFlad : any;; private idSpotify : any; //constructors constructor(){ diff --git a/src/FLAD/assets/icons/light_like.riv b/src/FLAD/assets/icons/light_like.riv deleted file mode 100644 index 8326bd450cc816279205dedac13293eb1f8144fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7522 zcmc&(ZBSI#89o=dsF7WE2?|RcSTwMTCYatTT4C?93#$|`K>@!eRT5XxU|?{KF_|h8 zYc$40V@)Dz1kqH3#xz<#rp^drrWGr#Gfmqc=@jFnnSR8Moh0ovwnN|dz31LNcbC2L zqtiNb59hpJ&vQQRdG3x2D(cHeG1e(D{FlKb70h&=7!dlEJ0?D z1MM!=iH&V&Xj8z>*z*CFkd#ujW_4rO9a^<2^i)`u9CdZSR-M?`+RkNNu|M+rZGM(0 zC!`JBsPa0VmVc`{v9YBOmG;?hX0PtcNM%WKVtV)Ucl_h9VQKQqQr-~!i=?gp%^lT= zjcs~&hTs0j{$f9+C7aTAn$m7~ZPyxG{Px~89U8_MQ}8Q1I3X!%Zd3C{AU-Aemg>aD z*4=&Lf}Q>Sf&vUugbCHxji062lVn@^_3+lfIBb|x-X#?<)^=gy^>AWYI?^nDt?W>cobM+S^7w z+shnsq2u1Ss#Is$)mqgpv1EC=>(iW9`)bEt-r%ca?3%y6@8UOm7GaM~lBZ|ZZXfb5 z_+r(dx)8$rOosS6Fl903F4Y72FrY^ZaLRk6f?uuPcOiG(*oXTj-g3ADlhP_K`C&(9 z;6t3X{Y#U7KnFYvUZ;K3Q=s<-_1a*U9-z~-{Kgytcqsk9X=K?7>N>%53Yn>;q?iPu+5KLQh?UJ#=EGuNLFAOsrwb z#IpUWk=dhV#&W2!;!tD7fimN9pv;kSsJG%!Z^eN!<8h$Ok#bmO#bKEh2g;1cfig$R zVTBck6;>Q5Gad)Z94Uv86^D=&2g;1cfig$RVXYO1wN@M`Gad)Z94UupD-O+894Ip$ z2g)2Nhp-iguoVZ&jK_g8N6KN76^Bh$94Ip$2g)2Nhs{%gwE1|4p`}uHVTXdT)9GUq*aUT8?pCj_wfYZUHlg%3%Yr}Z zz`wue_4QmCMALWLm!WA)27FmgP*=^jmH1BWP}S12zq>}EGcT3+D!w}zo$SMvCBEyA zJdSNQ-m`^QDKm9W*5C!iC@|g6$@%8Qr?tU){H`yT_y!-MY99NWeMenjFCU$*sOP5iXW2lSYDa57`{V>SRPN( zN0795aBvVEkfe28N+l$vArjL;paY@MLKL(+CHnIU`~fnsFfJt*avb1#SprsXOTod< zB^8Eyad=n?+Prl*yoy8MoHzjA`B^iZLc+|izw!zR`#-J_6VBj9x|EFjF?&e^fI_6!a6Nl*cz~}I4?fC=@P45813o;^-p<+npRirZ zW|+GTDAC4u;psSmE8n_Zxe6Y8tf&9yF9!I2@SNbkdOr8@MDQ4=qDwM)T*|T-toIQs z@QbNf(Tqi&oSBtzu+Tj`7I|DseGJw~#L9VMU+lcdb2=}l4|0r`0N9_c`6V+4}abJcxZ=%Pgq=+1kO2Ioy zBi@I5aB}2M{Xuz$lRfqcvR}R+)?)8N7V^VPLs0--rLhPv> zFZjTXFQtVWumd|Z2tQhArM2?`l^ z&vA^WH}S!fGfn#w@#MFBf{JLIh2v7Nw__acPxLz)<#8$D7%aGiVX1a+z|}L(0%4J- zw~3t}9t+*zG48nt7I|Dsa|{-~YQdx%dt&PwWwV zUBS`UZ3wti!{_>44&j1)^H8qdJd}$!hQ??&ms%N$o-||`^G+G6JOM`V`NAXfv=P^2 zMH`tU`M+2)qO`cG@8MxDfLRDSYqAR}tJ!rag(Q9+V(k%yHEKNy7=pf}E(KVwMzA=KTne2k5 znK8_7Oaue%IYsik=4V5#02cj&S^P0fzj+P0BW{tOmg4U@y1+@QX*=OJoOb%O&lmAi zCZ{N=Vr5h4KEU)Vd?di6yE-rzVf;jl1)foqx-i@j4!Nrvo@!k4OvwExo3m5m%K$xH z;Mr{GS2b)3wL(P68&V=GeM?F>EUjd755j+n`p}kuHm2JSNfM3|F+f5$4cUGvrBln2 LFhZpq=4Jl@p_85r diff --git a/src/FLAD/assets/icons/splash.png b/src/FLAD/assets/icons/splash.png index 8e0dc29614df6b80f0728fc988e3d9acce7aa042..7126405346f31dc6a478c0ef9e6652341428375f 100644 GIT binary patch literal 51768 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 literal 16002 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 diff --git a/src/FLAD/assets/icons/splashs.png b/src/FLAD/assets/icons/splashs.png new file mode 100644 index 0000000000000000000000000000000000000000..8e0dc29614df6b80f0728fc988e3d9acce7aa042 GIT binary patch literal 16002 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 literal 0 HcmV?d00001 diff --git a/src/FLAD/components/Card.tsx b/src/FLAD/components/Card.tsx index 65d9691..9ca470b 100644 --- a/src/FLAD/components/Card.tsx +++ b/src/FLAD/components/Card.tsx @@ -14,23 +14,17 @@ const SCREEN_WIDTH = Dimensions.get('window').width interface CardProps { title: string; image: any; - onSwipe: (direction: "left" | "right") => void; } type ContextType = { translateX: number; translateY: number; }; -const Card = ({ title, image, onSwipe} : CardProps) => { +const Card : React.FC = ({ title, image} : CardProps) => { const translateX = useSharedValue(0); const translateY = useSharedValue(0); - - const hapti = (() => { - - // Haptics.NotificationFeedbackType.Success - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium) - }); + const onGestureEvent = useAnimatedGestureHandler< PanGestureHandlerGestureEvent, ContextType @@ -47,10 +41,9 @@ const Card = ({ title, image, onSwipe} : CardProps) => { // translateX.value = withSpring(0); // translateY.value = withSpring(snapPoint(translateY.value,velocityY, snapPoints )) if (translateX.value > 160) { - hapti() - onSwipe("right"); + // onSwipe("right"); } else if (translateX.value < -160) { - onSwipe("left"); + // onSwipe("left"); } else { translateX.value = withSpring(0); translateY.value = withSpring(0); @@ -75,8 +68,6 @@ const Card = ({ title, image, onSwipe} : CardProps) => { ( translateX.value, [-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 2], [1, 0, 0]); - - return { opacity : opacityl, }; @@ -86,7 +77,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => { const opacityl = interpolate ( translateX.value, [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 4], - [0.85, 1, 1]); + [0.75, 1, 0.75]); return { opacity : opacityl, @@ -95,7 +86,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => { const opacDStyle = useAnimatedStyle(() => { const opacityl = interpolate ( translateY.value, - [-SCREEN_HEIGHT / 4, 0, SCREEN_HEIGHT / 4], + [-SCREEN_HEIGHT / 4, 0, SCREEN_HEIGHT / 2], [0, 0, 1]); return { opacity : opacityl, @@ -133,9 +124,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => { return ( - - - + { },opacRStyle]} > { },opacLStyle]} > @@ -171,7 +160,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => { > @@ -187,8 +176,7 @@ const styles = StyleSheet.create({ card : { justifyContent : 'center', alignItems : 'center', - borderColor : 'red', - borderWidth : 3, + }, image : { borderRadius : 24, @@ -202,6 +190,3 @@ const styles = StyleSheet.create({ export default Card; - - - diff --git a/src/FLAD/components/button/button.tsx b/src/FLAD/components/button/button.tsx index 7125873..737bba3 100644 --- a/src/FLAD/components/button/button.tsx +++ b/src/FLAD/components/button/button.tsx @@ -4,7 +4,7 @@ import Animated,{ Extrapolate, interpolate, useAnimatedGestureHandler, useAnimat import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler'; import * as Haptics from 'expo-haptics'; -import Icons from '../../assets/icons/icon'; +import Icons from '../../assets/icons/icons/icon'; import Rive, { Fit, RiveRef } from 'rive-react-native'; const {width : wWidht} = Dimensions.get("window"); diff --git a/src/FLAD/data/data.ts b/src/FLAD/data/data.ts index 805a6e5..6dcc56d 100644 --- a/src/FLAD/data/data.ts +++ b/src/FLAD/data/data.ts @@ -1,12 +1,12 @@ export const cards = [{ - name : "blue", - sourceUrl : "https://cdns-images.dzcdn.net/images/artist/399e7e760d8fedf3cc2891e9c0c41658/200x200-000000-80-0-0.jpg", - index : 3 - }, - { - name : "her", - sourceUrl : "https://images.unsplash.com/photo-1484589065579-248aad0d8b13?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1359&q=80", - index : 3 - } - - ] \ No newline at end of file + name : "blue", + sourceUrl : "https://i.ebayimg.com/images/g/rY0AAOSw97djEo2C/s-l500.jpg", + index : 3 +}, +{ + name : "her", + sourceUrl : "https://i.ebayimg.com/images/g/rY0AAOSw97djEo2C/s-l500.jpg", + index : 3 +} + +] \ No newline at end of file diff --git a/src/FLAD/navigation/Navigation.tsx b/src/FLAD/navigation/Navigation.tsx index b53d1bc..79cc464 100644 --- a/src/FLAD/navigation/Navigation.tsx +++ b/src/FLAD/navigation/Navigation.tsx @@ -4,6 +4,7 @@ import Home from '../screens/spot'; import FavoritePage from '../screens/favoritePage'; import { createStackNavigator } from '@react-navigation/stack'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +// import Spot from '../screens/spot'; export default function StackNavigation() { const Stack = createBottomTabNavigator(); @@ -12,10 +13,10 @@ export default function StackNavigation() { + }} > { if (direction === 'right') { // Swiped right - console.log("===================") } else if (direction === 'left') { // Swiped left } // update the state of the cards state when it remove thisy setCards(cards.filter((_, i) => i !== index)); - setcurrentCard(cards[cards.length -1]); }; - const hapti = (() => { - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy) - getValueFor(MY_SECURE_AUTH_STATE_KEY) - .then(key => { (key != null) ? getUserData(key) :console.log("error key is nullll") } ) ; - // Haptics.NotificationFeedbackType.Success - }); + // const hapti = (() => { + // Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy) + // getValueFor(MY_SECURE_AUTH_STATE_KEY) + // .then(key => { (key != null) ? getUserData(key) :console.log("error key is nullll") } ) ; + // // Haptics.NotificationFeedbackType.Success + // }); //////////////////////////////////////////////////////////////// - const [locationData, setLocationData] = useState(); - const [prevLocationData, setPrevLocationData] = useState(); - const [nearbyUsers, setNearbyUsers] = useState([]); - const [currentMusic, setCurrentMusic] = useState(""); - - async function getLocation() { - var { status } = await Location.requestForegroundPermissionsAsync(); - if (status !== 'granted') { - console.log('Permission to access location was denied'); - return; - } - - let currentLocation = await Location.getCurrentPositionAsync({}); - setLocationData({ - latitude: currentLocation.coords.latitude, - longitude: currentLocation.coords.longitude, - timestamp: currentLocation.timestamp - }); - }; - async function sendLocationToServer() { - getLocation(); - if (!locationData) return; - if (prevLocationData && locationData.latitude === prevLocationData.latitude && locationData.longitude === prevLocationData.longitude) { - return; - } - try { - const response = await axios.post( - 'http://localhost/api/users/david/nextToMe', - locationData - ); - - if (response.status !== 200) { - throw new Error('Failed to send location to server'); - } - - setPrevLocationData(locationData); - setNearbyUsers(response.data); - } catch (error) { - console.error(error); - } - }; + // const [locationData, setLocationData] = useState(); + // const [prevLocationData, setPrevLocationData] = useState(); + // const [nearbyUsers, setNearbyUsers] = useState([]); + // const [currentMusic, setCurrentMusic] = useState(""); + + // async function getLocation() { + // var { status } = await Location.requestForegroundPermissionsAsync(); + // if (status !== 'granted') { + // console.log('Permission to access location was denied'); + // return; + // } + + // let currentLocation = await Location.getCurrentPositionAsync({}); + // setLocationData({ + // latitude: currentLocation.coords.latitude, + // longitude: currentLocation.coords.longitude, + // timestamp: currentLocation.timestamp + // }); + // }; + // async function sendLocationToServer() { + // getLocation(); + // if (!locationData) return; + // if (prevLocationData && locationData.latitude === prevLocationData.latitude && locationData.longitude === prevLocationData.longitude) { + // return; + // } + // try { + // const response = await axios.post( + // 'http://localhost/api/users/david/nextToMe', + // locationData + // ); + + // if (response.status !== 200) { + // throw new Error('Failed to send location to server'); + // } + + // setPrevLocationData(locationData); + // setNearbyUsers(response.data); + // } catch (error) { + // console.error(error); + // } + // }; - setInterval(sendLocationToServer, 30000) + // setInterval(sendLocationToServer, 30000) return ( - - - + onSwipe(index, direction)} /> {/*