Added default PFP; Added PFP upload functionality; Show pfp in Navbar
This commit is contained in:
parent
fea9a0d0d2
commit
53edb8c7da
|
|
@ -1,4 +1,3 @@
|
||||||
const GameModel = require("../models/GameModel");
|
|
||||||
const PlayerModel = require("../models/PlayerModel");
|
const PlayerModel = require("../models/PlayerModel");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
const bcrypt = require("bcryptjs");
|
const bcrypt = require("bcryptjs");
|
||||||
|
const fs = require("node:fs/promises");
|
||||||
|
|
||||||
const UserModel = require("../models/UserModel");
|
const UserModel = require("../models/UserModel");
|
||||||
const BoardModel = require("../models/BoardModel");
|
const BoardModel = require("../models/BoardModel");
|
||||||
|
|
||||||
exports.listUsers = (req, res) => {
|
exports.listUsers = () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
UserModel.find({}, "-password")
|
UserModel.find({}, "-password")
|
||||||
.then((users) => {
|
.then((users) => {
|
||||||
|
|
@ -141,3 +142,30 @@ exports.addBoardToUser = ( board ) => {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.updateProfilePicture = ( userId, pfpFilename ) => {
|
||||||
|
return new Promise( ( resolve, reject ) => {
|
||||||
|
UserModel.findByIdAndUpdate( userId, { pfpFilename: pfpFilename } )
|
||||||
|
.then( ( userBefore ) => {
|
||||||
|
if( userBefore === null ){
|
||||||
|
let userNotFoundError = new Error(`No user found in session"`);
|
||||||
|
userNotFoundError.name = "NotFoundError";
|
||||||
|
throw userNotFoundError;
|
||||||
|
}
|
||||||
|
if( userBefore.pfpFilename !== null ){
|
||||||
|
return fs.rm( "public/uploads/" + userBefore.pfpFilename );
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then( () => {
|
||||||
|
return UserModel.findById( userId , {}, { new: true });
|
||||||
|
})
|
||||||
|
.then( ( user ) => {
|
||||||
|
resolve( user );
|
||||||
|
})
|
||||||
|
.catch( ( err ) => {
|
||||||
|
reject( err );
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ const UserSchema = new Schema({
|
||||||
},
|
},
|
||||||
password: { type: String, required: true, },
|
password: { type: String, required: true, },
|
||||||
boards: [{ type: Schema.Types.ObjectId, ref: "Board" }],
|
boards: [{ type: Schema.Types.ObjectId, ref: "Board" }],
|
||||||
|
pfpFilename: [{ type: String, required: false, default: null }],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Virtual for player's URL
|
// Virtual for player's URL
|
||||||
|
|
|
||||||
|
|
@ -60,21 +60,26 @@ const fileFilterFn = function( req, file, cb ){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let board = JSON.parse( req.body.board );
|
if( req.body.board ){
|
||||||
|
|
||||||
boardController.isBoardFromUser( board.boardId, req.session.user )
|
let board = JSON.parse( req.body.board );
|
||||||
.then( ( isFromUser ) => {
|
|
||||||
if( !isFromUser && board.boardId !== undefined ){
|
boardController.isBoardFromUser( board.boardId, req.session.user )
|
||||||
cb( new Error( "The associated board is not the users" ) );
|
.then( ( isFromUser ) => {
|
||||||
} else {
|
if( !isFromUser && board.boardId !== undefined ){
|
||||||
if( req.session.user === undefined ){
|
cb( new Error( "The associated board is not the users" ) );
|
||||||
cb( new Error( "Only logged in Users can upload pictures" ) );
|
} else {
|
||||||
return;
|
if( req.session.user === undefined ){
|
||||||
|
cb( new Error( "Only logged in Users can upload pictures" ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cb( null, true );
|
||||||
}
|
}
|
||||||
|
});
|
||||||
cb( null, true );
|
} else {
|
||||||
}
|
cb( null, true );
|
||||||
});
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,7 +89,7 @@ router.get("/", (req, res)=>{
|
||||||
if( req.session.user !== undefined ){
|
if( req.session.user !== undefined ){
|
||||||
userController.findUser( req.session.user )
|
userController.findUser( req.session.user )
|
||||||
.then( user => {
|
.then( user => {
|
||||||
res.send({success: true, user: { username: user.username } } );
|
res.send({success: true, user: { username: user.username, pfpFilename: user.pfpFilename } } );
|
||||||
})
|
})
|
||||||
.catch( err => {
|
.catch( err => {
|
||||||
console.debug(err);
|
console.debug(err);
|
||||||
|
|
@ -124,6 +129,7 @@ router.post("/login", (req, res)=>{
|
||||||
res.send({success: true, user: { username: req.session.user } } );
|
res.send({success: true, user: { username: req.session.user } } );
|
||||||
})
|
})
|
||||||
.catch( ( err ) => {
|
.catch( ( err ) => {
|
||||||
|
console.error( err );
|
||||||
res.send({success:false, error: "Error with logging you in" });
|
res.send({success:false, error: "Error with logging you in" });
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -240,19 +246,45 @@ router.get("/boards/:id", (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.get("/pfp/:filename", (req, res) => {
|
||||||
|
console.log("Getting pfp: ", req.params.filename);
|
||||||
|
let options = {
|
||||||
|
root: 'public/uploads',
|
||||||
|
dotfiles: 'deny',
|
||||||
|
headers: {
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.sendFile( req.params.filename, options );
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
router.post("/pfp", upload.single( "pfp" ), (req, res) => {
|
router.post("/pfp", upload.single( "pfp" ), (req, res) => {
|
||||||
if( req.session.user === undefined ){
|
if( req.session.user === undefined ){
|
||||||
res.send( { success: false, error: "Not logged in!" } );
|
res.send( { success: false, error: "Not logged in!" } );
|
||||||
} else {
|
} else {
|
||||||
let imageFile = null;
|
|
||||||
if( !req.file ){
|
if( !req.file ){
|
||||||
console.error( "No file attached" );
|
console.error( "No file attached" );
|
||||||
return;
|
throw new Error("No file attached to be saved" );
|
||||||
}
|
}
|
||||||
imageFile = req.file;
|
let imageFile = req.file;
|
||||||
return userController.updateProfilePicture( req.session.user, imageFile.filename )
|
return userController.updateProfilePicture( req.session.user, imageFile.filename )
|
||||||
.then( ( user ) => {
|
.then( ( user ) => {
|
||||||
res.send( { success: true, newProfilePicture: user.profilePicture } );
|
res.send( { success: true, newProfilePicture: user.pfpFilename } );
|
||||||
|
})
|
||||||
|
.catch( ( err ) => {
|
||||||
|
res.send( { success: false, error: err } );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.delete("/pfp", (req, res) => {
|
||||||
|
if( req.session.user === undefined ){
|
||||||
|
res.send( { success: false, error: "Not logged in!" } );
|
||||||
|
} else {
|
||||||
|
return userController.updateProfilePicture( req.session.user, null )
|
||||||
|
.then( ( _user ) => {
|
||||||
|
res.send( { success: true, } );
|
||||||
})
|
})
|
||||||
.catch( ( err ) => {
|
.catch( ( err ) => {
|
||||||
res.send( { success: false, error: err } );
|
res.send( { success: false, error: err } );
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ app.use(helmet(
|
||||||
"media-src": ["'self'", "data:"],
|
"media-src": ["'self'", "data:"],
|
||||||
"style-src-elem": ["'self'", "'unsafe-inline'"],
|
"style-src-elem": ["'self'", "'unsafe-inline'"],
|
||||||
"connect-src": ["'self'", "ws:"],
|
"connect-src": ["'self'", "ws:"],
|
||||||
"img-src": ["'self'", "blob:", "data:"],
|
"img-src": ["'self'", "blob:", "data:"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="100mm"
|
||||||
|
height="100mm"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||||
|
sodipodi:docname="PFP_Bear.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:zoom="0.7071068"
|
||||||
|
inkscape:cx="48.790367"
|
||||||
|
inkscape:cy="195.16147"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1008"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<ellipse
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:2.94695;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="ellipse9"
|
||||||
|
ry="8.7389574"
|
||||||
|
rx="7.3490396"
|
||||||
|
cy="0.21687971"
|
||||||
|
cx="-74.58239"
|
||||||
|
transform="matrix(-0.88593468,-0.46381003,-0.43331387,0.90124308,0,0)" />
|
||||||
|
<ellipse
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:2.94695;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="ellipse8"
|
||||||
|
ry="8.7389574"
|
||||||
|
rx="7.3490396"
|
||||||
|
cy="46.607407"
|
||||||
|
cx="15.560421"
|
||||||
|
transform="matrix(0.88593467,-0.46381004,0.43331386,0.90124309,0,0)" />
|
||||||
|
<path
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:3.20808;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 0.09642571,100.42076 C 7.8465924,67.218518 20.053978,42.128065 50.000563,42.128065 c 29.949567,0 42.15361,25.090329 49.904141,58.294115"
|
||||||
|
id="path1"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<circle
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path2"
|
||||||
|
cx="50"
|
||||||
|
cy="51.3937"
|
||||||
|
r="22.843529" />
|
||||||
|
<path
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 45.498078,55.013425 c 0.503992,-1.440484 2.975715,-1.436799 4.501822,-1.436799 1.526107,0 3.997459,-0.0036 4.501822,1.436799 0.75684,2.161377 -2.209427,5.387564 -4.499483,5.388153 -2.291078,5.89e-4 -5.260782,-3.225617 -4.504161,-5.388153 z"
|
||||||
|
id="path5"
|
||||||
|
sodipodi:nodetypes="sssss" />
|
||||||
|
<path
|
||||||
|
style="display:inline;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 49.983098,60.437125 c 0,3.055652 -0.219217,3.50138 -1.243542,4.092774 -1.678595,0.969137 -3.486678,-0.345521 -4.177109,-0.744142"
|
||||||
|
id="path6"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="display:inline;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 49.952982,60.437125 c 0,3.055652 0.219217,3.50138 1.243542,4.092774 1.678595,0.969137 3.486678,-0.345521 4.177109,-0.744142"
|
||||||
|
id="path7"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 56.5,44.887112 3.181598,-3.181598 3.180744,3.180745"
|
||||||
|
id="path9" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 36.5,44.887112 3.181598,-3.181598 3.180744,3.180745"
|
||||||
|
id="path10" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.1 KiB |
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="100mm"
|
||||||
|
height="100mm"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||||
|
sodipodi:docname="PFP_BearHead.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:zoom="0.7071068"
|
||||||
|
inkscape:cx="48.790367"
|
||||||
|
inkscape:cy="195.16147"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1008"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer2" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="Layer 2"
|
||||||
|
transform="translate(0.01884618,-0.22140619)">
|
||||||
|
<ellipse
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:4.42699;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="ellipse9"
|
||||||
|
ry="13.127905"
|
||||||
|
rx="11.039931"
|
||||||
|
cy="-10.383468"
|
||||||
|
cx="-78.467972"
|
||||||
|
transform="matrix(-0.88593467,-0.46381003,-0.43331387,0.90124309,0,0)" />
|
||||||
|
<ellipse
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:4.42699;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="ellipse8"
|
||||||
|
ry="13.127905"
|
||||||
|
rx="11.039931"
|
||||||
|
cy="36.007061"
|
||||||
|
cx="11.674847"
|
||||||
|
transform="matrix(0.88593467,-0.46381003,0.43331387,0.90124309,0,0)" />
|
||||||
|
<circle
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path2"
|
||||||
|
cx="50.009468"
|
||||||
|
cy="51.98246"
|
||||||
|
r="34.316185" />
|
||||||
|
<path
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 43.246556,57.420114 c 0.75711,-2.163936 4.470201,-2.158401 6.762761,-2.158401 2.292561,0 6.005093,-0.0054 6.762762,2.158401 1.136946,3.246879 -3.319062,8.093347 -6.759248,8.094232 -3.441721,8.75e-4 -7.902893,-4.845611 -6.766275,-8.094232 z"
|
||||||
|
id="path5"
|
||||||
|
sodipodi:nodetypes="sssss" />
|
||||||
|
<path
|
||||||
|
style="display:inline;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 49.984077,65.567745 c 0,4.590286 -0.329314,5.259871 -1.868084,6.148279 -2.521632,1.455864 -5.237785,-0.51905 -6.274968,-1.11787"
|
||||||
|
id="path6"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="display:inline;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 49.938836,65.567745 c 0,4.590286 0.329314,5.259871 1.868083,6.148279 2.521632,1.455864 5.237784,-0.51905 6.274969,-1.11787"
|
||||||
|
id="path7"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 59.773948,42.208084 4.779484,-4.779484 4.778202,4.778204"
|
||||||
|
id="path9" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.50669;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 29.729393,42.208084 4.779485,-4.779484 4.778201,4.778204"
|
||||||
|
id="path10" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="100mm"
|
||||||
|
height="100mm"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||||
|
sodipodi:docname="PFP_draft1.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:zoom="0.3535534"
|
||||||
|
inkscape:cx="-465.27625"
|
||||||
|
inkscape:cy="96.16652"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1008"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 8.2680968e-4,99.998029 C 7.7658401,71.018605 19.996612,49.119274 50.000563,49.119274 c 30.00694,0 42.234362,21.899223 49.999737,50.879996"
|
||||||
|
id="path1"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<circle
|
||||||
|
style="fill:#e86a92;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path2"
|
||||||
|
cx="50"
|
||||||
|
cy="31.188124"
|
||||||
|
r="22.843529" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -87,6 +87,8 @@ $modal-content-bg: $dark-blue;
|
||||||
|
|
||||||
$font-family-base: "Urbanist";
|
$font-family-base: "Urbanist";
|
||||||
|
|
||||||
|
$enable-caret: false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 2. Include any default variable overrides here
|
// 2. Include any default variable overrides here
|
||||||
|
|
@ -189,3 +191,7 @@ $utilities: map-merge(
|
||||||
.image-contain{
|
.image-contain{
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pfp{
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import { useUserStore } from "@/stores/UserStore";
|
||||||
|
import GenericMultiButtonModal from '@/components/views/GenericMultiButtonModal.vue';
|
||||||
|
import { openModal } from "@/services/util";
|
||||||
|
import ProfilePicture from '@/components/blocks/ProfilePicture.vue';
|
||||||
|
|
||||||
const emit = defineEmits(["profilePictureChanged"]);
|
|
||||||
|
|
||||||
let uploadedFileUrl = ref(null);
|
let uploadedFileObj = ref(null);
|
||||||
|
let uploadingInProcess = ref(false);
|
||||||
|
let imageInput = ref(null);
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
function newImageUploaded( event ){
|
function newImageUploaded( event ){
|
||||||
let files = event.target.files || event.dataTransfer.files;
|
let files = event.target.files || event.dataTransfer.files;
|
||||||
|
|
@ -16,14 +22,43 @@ function newImageUploaded( event ){
|
||||||
data: files[0],
|
data: files[0],
|
||||||
url: URL.createObjectURL( files[0] ),
|
url: URL.createObjectURL( files[0] ),
|
||||||
};
|
};
|
||||||
uploadedFileUrl.value = fileObj;
|
uploadedFileObj.value = fileObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
function revealAnswer(){
|
function saveProfilePicture(){
|
||||||
emit("profilePictureChanged");
|
if( uploadedFileObj.value === null || uploadingInProcess.value === true ){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uploadingInProcess.value = true;
|
||||||
|
userStore.saveProfilePicture( uploadedFileObj.value.data )
|
||||||
|
.finally( () => {
|
||||||
|
uploadingInProcess.value = false;
|
||||||
|
resetUploadedFileObj();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
revealAnswer();
|
function deleteProfilePicture(){
|
||||||
|
openModal('confirmDeletePfpModal');
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetUploadedFileObj(){
|
||||||
|
uploadedFileObj.value = null;
|
||||||
|
imageInput.value.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleModalButtonClick( buttonIndex ){
|
||||||
|
switch( buttonIndex ){
|
||||||
|
case 0:
|
||||||
|
userStore.deleteProfilePicture()
|
||||||
|
.finally( () => {
|
||||||
|
uploadedFileObj.value = null;
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -36,23 +71,51 @@ revealAnswer();
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-2">
|
<div class="col-auto">
|
||||||
<div class="ratio ratio-16x9">
|
<ProfilePicture
|
||||||
<img src="" alt="Current Profile Picture">
|
:srcOverride="(uploadedFileObj !== null ? uploadedFileObj.url : null )"
|
||||||
</div>
|
:isPreview="uploadedFileObj !== null"
|
||||||
|
@previewDiscarded="resetUploadedFileObj()"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col-auto border-start">
|
||||||
<div class="row">
|
<div class="h-100 d-flex flex-column justify-content-evenly">
|
||||||
<div class="col">
|
<div>
|
||||||
<img src="" alt="Standard Profile Picture">
|
<label class="form-label fs-5" for="question-image">Upload new profile picture</label>
|
||||||
|
<input ref="imageInput" class="form-control bg-dark-blue" type="file" name="question-image" id="question-image" @change="newImageUploaded" accept="image/*">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-pink-accent-primary me-3" :disabled="uploadedFileObj === null" @click="saveProfilePicture">
|
||||||
|
<font-awesome-icon v-if="uploadingInProcess" icon="fa-solid fa-spinner" spin/>
|
||||||
|
<font-awesome-icon v-else icon="fa-solid fa-floppy-disk" />
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-danger" :disabled="userStore.pfpFilename === null" @click="deleteProfilePicture">
|
||||||
|
<font-awesome-icon icon="fa-solid fa-floppy-disk" />
|
||||||
|
Delete Current Profile Picture
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="form-label fs-4 mt-3" for="question-image">Upload new profile picture</label>
|
|
||||||
<input class="form-control bg-dark-blue" type="file" name="question-image" id="question-image" @change="newImageUploaded( questionIndex, $event )" accept="image/*">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
<GenericMultiButtonModal
|
||||||
|
:id="'confirmDeletePfpModal'"
|
||||||
|
:hasTitle="true"
|
||||||
|
:title="'Are you sure?'"
|
||||||
|
:modalText="'Are you sure you want to delete your current profile picture?'"
|
||||||
|
:buttonList="[
|
||||||
|
{
|
||||||
|
text: 'Yes, delete!',
|
||||||
|
emitsEvent: 'discardClicked',
|
||||||
|
bgColorClass: 'btn-danger',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Cancel',
|
||||||
|
bgColorClass: 'btn-pink-accent-primary',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
@buttonClicked="handleModalButtonClick"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { useUserStore } from "@/stores/UserStore"
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
srcOverride: {
|
||||||
|
type: [String, null],
|
||||||
|
default: null,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
sizingClasses: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ["pfp-sizing"],
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
isPreview: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["previewDiscarded"]);
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
let protocol = ('https:' == document.location.protocol ? 'https://' : 'http://');
|
||||||
|
let hostname = window.location.hostname;
|
||||||
|
if( window.location.hostname.includes("localhost" ) ){
|
||||||
|
hostname += ':3000';
|
||||||
|
}
|
||||||
|
const API_URL = `${protocol}${hostname}/api`;
|
||||||
|
|
||||||
|
const pfpSrc = computed( () => {
|
||||||
|
if( props.srcOverride !== null ){
|
||||||
|
return props.srcOverride;
|
||||||
|
} else if( userStore.pfpFilename === null ){
|
||||||
|
return "/src/webapp/assets/images/PFP_BearHead.svg";
|
||||||
|
} else {
|
||||||
|
return `${API_URL}/user/pfp/${userStore.pfpFilename}`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="border border-1 border-white rounded-3 overflow-hidden">
|
||||||
|
<img :src="pfpSrc" alt="Profile Picture of the user" class="pfp" :class="sizingClasses" />
|
||||||
|
<div v-show="props.isPreview" class="position-relative">
|
||||||
|
<span class="position-absolute bottom-0 end-0 bg-black bg-opacity-50 px-1 rounded-2">
|
||||||
|
Preview
|
||||||
|
<font-awesome-icon icon="fa-solid fa-rotate-left" size="sm" @click="emit('previewDiscarded')" title="Discard uploaded image" class="pointer"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.pfp-sizing{
|
||||||
|
height: 10rem;
|
||||||
|
width: 10rem;
|
||||||
|
max-height: 100vh;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
.pfp-sizing-navbar{
|
||||||
|
height: 2em;
|
||||||
|
width: 2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useUserStore } from '@/stores/UserStore';
|
import { useUserStore } from '@/stores/UserStore';
|
||||||
|
import ProfilePicture from '@/components/blocks/ProfilePicture.vue';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
|
@ -67,7 +68,13 @@ function logoutButtonClicked(_event){
|
||||||
<div v-if="userStore.loggedIn">
|
<div v-if="userStore.loggedIn">
|
||||||
<div class="dropdown text-center">
|
<div class="dropdown text-center">
|
||||||
<a class="dropdown-toggle text-decoration-none" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<a class="dropdown-toggle text-decoration-none" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
{{ userStore.username }}
|
<div class="d-flex align-items-center justify-content-around">
|
||||||
|
<font-awesome-icon icon="fa-solid fa-angle-down" size="sm" class="me-2"/>
|
||||||
|
<span class="me-1">{{ userStore.username }}</span>
|
||||||
|
<ProfilePicture
|
||||||
|
:sizingClasses="['pfp-sizing-navbar']"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-dark bg-dark-blue">
|
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-dark bg-dark-blue">
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -96,7 +103,13 @@ function logoutButtonClicked(_event){
|
||||||
<div v-if="userStore.loggedIn">
|
<div v-if="userStore.loggedIn">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<a class="dropdown-toggle text-decoration-none" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<a class="dropdown-toggle text-decoration-none" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
{{ userStore.username }}
|
<div class="d-flex align-items-center justify-content-around">
|
||||||
|
<font-awesome-icon icon="fa-solid fa-angle-down" size="sm" class="me-2"/>
|
||||||
|
<span class="me-1">{{ userStore.username }}</span>
|
||||||
|
<ProfilePicture
|
||||||
|
:sizingClasses="['pfp-sizing-navbar']"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-dark bg-dark-blue">
|
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-dark bg-dark-blue">
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -127,4 +140,8 @@ function logoutButtonClicked(_event){
|
||||||
.nav-logo{
|
.nav-logo{
|
||||||
height: 3.75em;
|
height: 3.75em;
|
||||||
}
|
}
|
||||||
|
.pfp-sizing-navbar{
|
||||||
|
height: 2em;
|
||||||
|
width: 2em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, computed } from 'vue';
|
import { onMounted, ref, computed } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { Modal } from "bootstrap";
|
import { openModal } from "@/services/util";
|
||||||
|
|
||||||
import BoardEntryEditView from '@/components/views/BoardEntryEditView.vue';
|
import BoardEntryEditView from '@/components/views/BoardEntryEditView.vue';
|
||||||
import CategoryEditView from '@/components/views/CategoryEditView.vue';
|
import CategoryEditView from '@/components/views/CategoryEditView.vue';
|
||||||
|
|
@ -192,13 +192,6 @@ function exitCreatePage(){
|
||||||
router.push("/profile");
|
router.push("/profile");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Maybe extract
|
|
||||||
function openModal( modalId ){
|
|
||||||
let modalElement = document.getElementById( modalId );
|
|
||||||
let modalInstance = Modal.getOrCreateInstance( modalElement );
|
|
||||||
modalInstance.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleBottomView(){
|
function toggleBottomView(){
|
||||||
showingBottomView.value = !showingBottomView.value;
|
showingBottomView.value = !showingBottomView.value;
|
||||||
}
|
}
|
||||||
|
|
@ -328,7 +321,6 @@ if( route.params.boardId !== undefined ){
|
||||||
:buttonList="[
|
:buttonList="[
|
||||||
{
|
{
|
||||||
text: 'Yes, discard!',
|
text: 'Yes, discard!',
|
||||||
emitsEvent: 'discardClicked',
|
|
||||||
bgColorClass: 'btn-danger',
|
bgColorClass: 'btn-danger',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,10 @@ const props = defineProps({
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
text: "Ok",
|
text: "Ok",
|
||||||
emitsEvent: "b1Clicked",
|
|
||||||
bgColorClass: "btn-pink-accent-primary",
|
bgColorClass: "btn-pink-accent-primary",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "Cancel",
|
text: "Cancel",
|
||||||
emitsEvent: "b2Clicked",
|
|
||||||
bgColorClass: "btn-outline-danger",
|
bgColorClass: "btn-outline-danger",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ import { createPinia } from "pinia";
|
||||||
import { FontAwesomeIcon, FontAwesomeLayers } from "@fortawesome/vue-fontawesome";
|
import { FontAwesomeIcon, FontAwesomeLayers } from "@fortawesome/vue-fontawesome";
|
||||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||||
import { faDragon, faRightToBracket, faUsers, faUserPlus, faSpinner, faPlusSquare, faBorderAll, faPen, faTrash, faAngleDown, faAngleUp,
|
import { faDragon, faRightToBracket, faUsers, faUserPlus, faSpinner, faPlusSquare, faBorderAll, faPen, faTrash, faAngleDown, faAngleUp,
|
||||||
faPlus, faMinus, faAngleRight, faSquare, faPlay, faCircleExclamation, faSquareCheck, faSquareMinus, faHandPointer } from "@fortawesome/free-solid-svg-icons";
|
faPlus, faMinus, faAngleRight, faSquare, faPlay, faCircleExclamation, faSquareCheck, faSquareMinus, faHandPointer, faFloppyDisk,
|
||||||
|
faEye, faRotateLeft } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { faCircleUser, faSquarePlus } from "@fortawesome/free-regular-svg-icons";
|
import { faCircleUser, faSquarePlus } from "@fortawesome/free-regular-svg-icons";
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -40,6 +41,9 @@ library.add({
|
||||||
faPlay,
|
faPlay,
|
||||||
faCircleExclamation,
|
faCircleExclamation,
|
||||||
faHandPointer,
|
faHandPointer,
|
||||||
|
faFloppyDisk,
|
||||||
|
faEye,
|
||||||
|
faRotateLeft,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,4 +101,22 @@ export default class UserService{
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveNewProfilePicture( pfpFormData ){
|
||||||
|
return axios.post(
|
||||||
|
API_URL + "/user/pfp",
|
||||||
|
pfpFormData,
|
||||||
|
{
|
||||||
|
withCredentials: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteProfilePicture( ){
|
||||||
|
return axios.delete(
|
||||||
|
API_URL + "/user/pfp",
|
||||||
|
{
|
||||||
|
withCredentials: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
import { Modal } from "bootstrap";
|
||||||
|
|
||||||
import BoardEntry from "@/models/BoardEntry";
|
import BoardEntry from "@/models/BoardEntry";
|
||||||
import Category from "@/models/Category";
|
import Category from "@/models/Category";
|
||||||
import Board from "@/models/Board";
|
import Board from "@/models/Board";
|
||||||
|
|
||||||
|
|
||||||
export function boardResponseToBoardModel( boardResponse ){
|
export function boardResponseToBoardModel( boardResponse ){
|
||||||
let categories = [];
|
let categories = [];
|
||||||
|
|
||||||
|
|
@ -29,3 +32,9 @@ export function boardResponseToBoardModel( boardResponse ){
|
||||||
|
|
||||||
return new Board( boardResponse._id, boardResponse.name, categories );
|
return new Board( boardResponse._id, boardResponse.name, categories );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function openModal( modalId ){
|
||||||
|
let modalElement = document.getElementById( modalId );
|
||||||
|
let modalInstance = Modal.getOrCreateInstance( modalElement );
|
||||||
|
modalInstance.show();
|
||||||
|
}
|
||||||
|
|
@ -247,10 +247,10 @@ export const useGameStore = defineStore('game', {
|
||||||
this.websocketConnection.onerror = ( _event ) => {
|
this.websocketConnection.onerror = ( _event ) => {
|
||||||
console.error("Websocket Error");
|
console.error("Websocket Error");
|
||||||
};
|
};
|
||||||
this.websocketConnection.onclose = ( event ) => {
|
this.websocketConnection.onclose = ( _event ) => {
|
||||||
clearInterval( this.keepAliveInterval );
|
clearInterval( this.keepAliveInterval );
|
||||||
this.keepAliveInterval = undefined;
|
this.keepAliveInterval = undefined;
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
userStore.resetInitialUserDataPromise();
|
userStore.resetInitialUserDataPromise();
|
||||||
userStore.initialUserPromise
|
userStore.initialUserPromise
|
||||||
.then( ( userData ) => {
|
.then( ( userData ) => {
|
||||||
|
|
@ -317,7 +317,7 @@ export const useGameStore = defineStore('game', {
|
||||||
this.players = data.payload.players;
|
this.players = data.payload.players;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.addSocketListener("payloadIncomplete", ( data ) => {
|
this.addSocketListener("payloadIncomplete", ( _data ) => {
|
||||||
console.error("Invalid or Incomplete Payload!");
|
console.error("Invalid or Incomplete Payload!");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ export const useUserStore = defineStore('user', {
|
||||||
loggedIn: false,
|
loggedIn: false,
|
||||||
username: "",
|
username: "",
|
||||||
admin: false,
|
admin: false,
|
||||||
|
pfpFilename: null,
|
||||||
initialUserPromise: new Promise( (resolve, reject ) => {
|
initialUserPromise: new Promise( (resolve, reject ) => {
|
||||||
uService.getUserFromSession()
|
uService.getUserFromSession()
|
||||||
.then( res => {
|
.then( res => {
|
||||||
|
|
@ -43,6 +44,7 @@ export const useUserStore = defineStore('user', {
|
||||||
setUser( user ){
|
setUser( user ){
|
||||||
this.loggedIn = true;
|
this.loggedIn = true;
|
||||||
this.username = user.username;
|
this.username = user.username;
|
||||||
|
this.pfpFilename = user.pfpFilename;
|
||||||
},
|
},
|
||||||
resetInitialUserDataPromise(){
|
resetInitialUserDataPromise(){
|
||||||
this.initialUserPromise = new Promise( (resolve, reject ) => {
|
this.initialUserPromise = new Promise( (resolve, reject ) => {
|
||||||
|
|
@ -59,6 +61,39 @@ export const useUserStore = defineStore('user', {
|
||||||
reject( err );
|
reject( err );
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
saveProfilePicture( imageData ){
|
||||||
|
return new Promise( ( resolve, reject ) => {
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append( "pfp", imageData );
|
||||||
|
this.userService.saveNewProfilePicture( formData )
|
||||||
|
.then( ( response ) => {
|
||||||
|
this.pfpFilename = response.data.newProfilePicture;
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch( ( error ) => {
|
||||||
|
console.error( error );
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteProfilePicture(){
|
||||||
|
return new Promise( ( resolve, reject ) => {
|
||||||
|
this.userService.deleteProfilePicture()
|
||||||
|
.then( ( response ) => {
|
||||||
|
if( response.data.success ){
|
||||||
|
this.pfpFilename = null;
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
console.warn( "Profile picture could not be deleted" );
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch( ( error ) => {
|
||||||
|
console.error( error );
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
Loading…
Reference in New Issue