install file picker and fix UI bugs

This commit is contained in:
luisa.bellitto 2025-06-21 20:19:58 +02:00 committed by Rudi Regentonne
parent df9b44d061
commit 3a0a3e4331
6 changed files with 121 additions and 64 deletions

View file

@ -21,6 +21,7 @@
"react-router-dom": "^7.6.2",
"react-scripts": "5.0.1",
"typescript": "^4.4.2",
"use-file-picker": "^2.1.4",
"web-vitals": "^2.1.0"
},
"scripts": {

View file

@ -1,5 +1,4 @@
import * as React from "react";
import { useRef, useState } from "react";
import {
Button,
styled,
@ -10,12 +9,15 @@ import {
IconButton,
Avatar,
Box,
Divider,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import EditSquareIcon from "@mui/icons-material/EditSquare";
import "../styles/colors.css";
import "../styles/fonts.css";
import "./changeAvatarDialog.css";
import ButtonPrimary from "./ButtonPrimary";
import { useFilePicker } from "use-file-picker";
const BootstrapDialog = styled(Dialog)(({ theme }) => ({
"& .MuiDialogContent-root": {
@ -27,25 +29,20 @@ const BootstrapDialog = styled(Dialog)(({ theme }) => ({
}));
export default function CustomizedDialogs() {
const { openFilePicker, filesContent, loading } = useFilePicker({
accept: ".png, .jpg, .jpeg",
multiple: false,
readAs: "DataURL",
limitFilesConfig: { max: 1 },
});
const inputFile = useRef<HTMLInputElement | null>(null);
const openFileExplorer = () => {
// `current` points to the mounted file input element
if (inputFile.current) {
inputFile.current.click();
const setImageURL = ({ newImage = false }: { newImage: boolean }) => {
if (newImage) {
return filesContent[0].content;
}
};
const [selectedImage, setSelectedImage] = useState<File | null>(null);
const setImageURL = (selectedImage: File | null) => {
if (selectedImage !== null) {
return URL.createObjectURL(selectedImage);
}
//TODO: If no image is selected, return the image already in the database or undefined
// TODO: If no image is selected, return the image already in the database or undefined
return undefined;
}
};
const [open, setOpen] = React.useState(false);
@ -53,19 +50,25 @@ export default function CustomizedDialogs() {
setOpen(true);
};
const handleClose = () => {
setSelectedImage(null); // Reset the selected image when closing
setImageURL({ newImage: false }); // Reset the selected image when closing
setOpen(false);
};
const handleSaveChanges = () => {
setOpen(false);
}
};
return (
<React.Fragment>
<Button onClick={handleClickOpen}>
<Avatar
alt="Username"
src={setImageURL(selectedImage)}
// current code does not work yet
// TODO: If no image is selected, return the image already in the database or undefined
src={
filesContent.length > 0
? setImageURL({ newImage: true })
: undefined
}
className="profile-avatar"
>
U
@ -76,7 +79,11 @@ export default function CustomizedDialogs() {
aria-labelledby="change-profile-picture-dialog"
open={open}
>
<DialogTitle sx={{ m: 0, p: 2 }} id="change-profile-picture-dialog">
<DialogTitle
className="small-title orange-text"
sx={{ m: 1.5, p: 2 }}
id="change-profile-picture-dialog"
>
Change Profile Picture
</DialogTitle>
<IconButton
@ -91,7 +98,8 @@ export default function CustomizedDialogs() {
>
<CloseIcon />
</IconButton>
<DialogContent dividers>
<Divider variant="middle" className="divider" />
<DialogContent>
<Box
sx={{
display: "flex",
@ -103,32 +111,32 @@ export default function CustomizedDialogs() {
maxHeight: "30rem",
}}
>
{selectedImage && (
{filesContent.map((file) => (
<img
src={URL.createObjectURL(selectedImage)}
alt="Profile Picture"
style={{maxWidth: "30rem", maxHeight: "30rem" , width: "100%", height: "100%", objectFit: "cover"}}
/>
)}
alt={file.name}
src={file.content}
style={{
maxWidth: "30rem",
maxHeight: "30rem",
width: "100%",
height: "100%",
objectFit: "cover",
}}
></img>
))}
</Box>
<IconButton aria-label="upload picture" onClick={openFileExplorer}>
<EditSquareIcon />
<input
type="file"
id="file"
onChange={(event) => {
console.log(event.target.files ? [0] : undefined); // Log the selected file
if (event.target.files && event.target.files[0]) {
setSelectedImage(event.target.files[0]); // Update the state with the selected file
}
}}
/>
</IconButton>
<div className="change-avatar-button">
<IconButton
aria-label="upload picture"
onClick={() => openFilePicker()}
>
<EditSquareIcon className="edit-icon" />
</IconButton>
</div>
</DialogContent>
<Divider variant="middle" className="divider" />
<DialogActions>
<Button autoFocus onClick={handleSaveChanges}>
Save changes
</Button>
<ButtonPrimary value="Save Changes" onClick={handleSaveChanges} />
</DialogActions>
</BootstrapDialog>
</React.Fragment>

View file

@ -4,9 +4,43 @@
}
.profile-image-large {
width: 20rem;
height: 20rem;
object-fit: cover;
border-radius: 8px;
max-width: 30rem;
max-height: 30rem;
width: 100%;
height: 100%;
object-fit: "cover";
}
.css-10d30g3-MuiPaper-root-MuiDialog-paper {
background-color: var(--transparent-dark-blue);
backdrop-filter: blur(15px);
border-radius: 1rem;
}
.css-10d30g3-MuiPaper-root-MuiDialog-paper {
color: var(--Rotkehlchen-orange-default);
}
.profile-avatar {
width: 40px;
height: 40px;
background-color: aqua;
}
.css-53g0n7-MuiButtonBase-root-MuiIconButton-root {
color: var(--Rotkehlchen-orange-default);
}
.change-avatar-button {
display: flex;
justify-content: end;
align-items: end;
}
@media screen and (min-width: 768px) {
.profile-avatar {
width: 5rem;
height: 5rem;
background-color: var(--Rotkehlchen-yellow-default);
}
}

View file

@ -31,6 +31,7 @@
.numeral-data {
display: flex;
flex-direction: row;
justify-content: space-around;
font-size: 18px;
font-weight: 600;
color: var(--Rotkehlchen-gray);
@ -49,12 +50,6 @@
font-weight: 500;
}
.profile-avatar {
width: 40px;
height: 40px;
background-color: aqua;
}
.profile-username {
font-weight: 700;
font-size: 1.2rem;
@ -99,7 +94,7 @@
.numeral-data {
display: flex;
flex-direction: column;
margin-top: 2rem;
margin-top: 1rem;
font-weight: 700;
font-size: 2rem;
}
@ -115,10 +110,4 @@
flex-direction: column;
margin: 1rem;
}
.profile-avatar {
width: 5rem;
height: 5rem;
background-color: aqua;
}
}

View file

@ -26,3 +26,14 @@ body{
z-index: -1;
background-attachment: fixed;
}
.blue-background {
border-radius: 1rem;
background-color: var(--transparent-dark-blue);
backdrop-filter: blur(8px);
height: fit-content;
}
.edit-icon {
color: var(--Rotkehlchen-brown-light)
}

View file

@ -4830,6 +4830,13 @@ file-loader@^6.2.0:
loader-utils "^2.0.0"
schema-utils "^3.0.0"
file-selector@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-2.1.2.tgz#fe7c7ee9e550952dfbc863d73b14dc740d7de8b4"
integrity sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==
dependencies:
tslib "^2.7.0"
filelist@^1.0.4:
version "1.0.4"
resolved "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz"
@ -9385,7 +9392,7 @@ tslib@^1.8.1:
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.3:
tslib@^2.0.3, tslib@^2.7.0:
version "2.8.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@ -9601,6 +9608,13 @@ url-parse@^1.5.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
use-file-picker@^2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/use-file-picker/-/use-file-picker-2.1.4.tgz#2c005b005b627af30d2cfd1aeb3c01e952d390d1"
integrity sha512-b4lZiAWrXi/QNUjTv0Q+S0hVcSFXIC9c4EUcrnYtdPtgK3T6xfi01YLVamhoY0k9WM9Cg4KyxD1TtM1e8dzQAQ==
dependencies:
file-selector "^2.1.2"
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"