perf: displayDetails pref is now in LocalStorage

This commit is contained in:
bsourisse 2023-08-10 18:54:09 +02:00
parent b96bfbff13
commit 045f1d1576
5 changed files with 84 additions and 158 deletions

View file

@ -1,15 +1,61 @@
//Lib
import React from 'react';
import { useState } from 'react';
import classes from './Repo.module.css';
import { IconSettings, IconInfoCircle } from '@tabler/icons-react';
import {
IconSettings,
IconInfoCircle,
IconChevronDown,
IconChevronUp,
} from '@tabler/icons-react';
import timestampConverter from '../../helpers/functions/timestampConverter';
import StorageBar from '../UI/StorageBar/StorageBar';
import QuickCommands from './QuickCommands/QuickCommands';
export default function Repo(props) {
//Load displayDetails from LocalStorage
const displayDetailsFromLS = () => {
try {
if (
localStorage.getItem('displayDetailsRepo' + props.id) === null
) {
localStorage.setItem(
'displayDetailsRepo' + props.id,
JSON.stringify(true)
);
return true;
} else {
return JSON.parse(
localStorage.getItem('displayDetailsRepo' + props.id)
);
}
} catch (error) {
console.log(
'LocalStorage error, key',
'displayDetailsRepo' + props.id,
'will be removed. Try again.',
'Error message on this key : ',
error
);
localStorage.removeItem('displayDetailsRepo' + props.id);
}
};
//States
const [displayDetails, setDisplayDetails] = useState(displayDetailsFromLS);
//BUTTON : Display or not repo details for ONE repo
const displayDetailsForOneHandler = (boolean) => {
//Update localStorage
localStorage.setItem(
'displayDetailsRepo' + props.id,
JSON.stringify(boolean)
);
setDisplayDetails(boolean);
};
return (
<>
{props.displayDetails ? (
{displayDetails ? (
<>
<div className={classes.RepoOpen}>
<div className={classes.openFlex}>
@ -127,6 +173,27 @@ export default function Repo(props) {
</div>
</>
)}
{displayDetails ? (
<div className={classes.chevron}>
<IconChevronUp
color='#494b7a'
size={28}
onClick={() => {
displayDetailsForOneHandler(false);
}}
/>
</div>
) : (
<div className={classes.chevron}>
<IconChevronDown
color='#494b7a'
size={28}
onClick={() => {
displayDetailsForOneHandler(true);
}}
/>
</div>
)}
</>
);
}

View file

@ -35,7 +35,7 @@
margin: 20px 0px 0px 0px;
padding: 15px;
border-radius: 5px;
transition: max-height 0.2s linear;
transition: max-height 0.1s linear;
overflow: visible;
/* Need to display comment on hover (which is position : absolute) */
position: relative;
@ -193,6 +193,17 @@
opacity: 1;
}
.chevron {
margin: auto;
}
.chevron :focus,
.chevron :hover {
cursor: pointer;
filter: invert(27%) sepia(82%) saturate(2209%) hue-rotate(240deg)
brightness(99%) contrast(105%);
}
/* MOBILE */
@media all and (max-width: 1000px) {
.tabInfo {

View file

@ -1,7 +1,7 @@
//Lib
import classes from './RepoList.module.css';
import { useState, useEffect, useRef } from 'react';
import { IconPlus, IconChevronDown, IconChevronUp } from '@tabler/icons-react';
import { useState, useEffect } from 'react';
import { IconPlus } from '@tabler/icons-react';
import { useRouter } from 'next/router';
import Link from 'next/link';
import useSWR, { useSWRConfig } from 'swr';
@ -48,7 +48,6 @@ export default function RepoList() {
////States
const [displayRepoAdd, setDisplayRepoAdd] = useState(false);
const [displayRepoEdit, setDisplayRepoEdit] = useState(false);
const [isLoading, setIsLoading] = useState(false);
////Functions
@ -67,32 +66,6 @@ export default function RepoList() {
return <ToastContainer />;
}
//BUTTON : Display or not repo details for ONE repo
const displayDetailsForOneHandler = async (id, boolean) => {
setIsLoading(true);
await fetch('/api/repo/id/' + id + '/displayDetails', {
method: 'PUT',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({ displayDetails: boolean }),
})
.then((response) => {
if (response.ok) {
mutate('/api/repo');
setIsLoading(false);
} else {
setIsLoading(false);
toast.error('API error', toastOptions);
}
})
.catch((error) => {
console.log(error);
setIsLoading(false);
toast.error('API error', toastOptions);
});
};
//BUTTON : Display RepoManage component box for ADD
const manageRepoAddHandler = () => {
router.replace('/manage-repo/add');
@ -131,45 +104,11 @@ export default function RepoList() {
storageSize={repo.storageSize}
storageUsed={repo.storageUsed}
sshPublicKey={repo.sshPublicKey}
displayDetails={repo.displayDetails}
unixUser={repo.unixUser}
comment={repo.comment}
lanCommand={repo.lanCommand}
repoManageEditHandler={() => repoManageEditHandler(repo.id)}
></Repo>
{repo.displayDetails ? (
<div className={classes.chevron}>
{isLoading ? (
<IconChevronUp color='#494b7a' size={28} />
) : (
<IconChevronUp
color='#494b7a'
size={28}
onClick={() => {
displayDetailsForOneHandler(repo.id, false);
// tell all SWRs with this key to revalidate
mutate('/api/repo');
}}
/>
)}
</div>
) : (
<div className={classes.chevron}>
{isLoading ? (
<IconChevronDown color='#494b7a' size={28} />
) : (
<IconChevronDown
color='#494b7a'
size={28}
onClick={() => {
displayDetailsForOneHandler(repo.id, true);
// tell all SWRs with this key to revalidate
mutate('/api/repo');
}}
/>
)}
</div>
)}
</>
);
});

View file

@ -112,17 +112,6 @@
transform: scale(0.96);
}
.chevron {
margin: auto;
}
.chevron :focus,
.chevron :hover {
cursor: pointer;
filter: invert(27%) sepia(82%) saturate(2209%) hue-rotate(240deg)
brightness(99%) contrast(105%);
}
@media all and (max-width: 1000px) {
.newRepoButton {
display: none;

View file

@ -1,80 +0,0 @@
import { promises as fs } from 'fs';
import path from 'path';
import { authOptions } from '../../../auth/[...nextauth]';
import { getServerSession } from 'next-auth/next';
export default async function handler(req, res) {
if (req.method == 'PUT') {
//Verify that the user is logged in.
const session = await getServerSession(req, res, authOptions);
if (!session) {
res.status(401).json({ message: 'You must be logged in.' });
return;
}
//The data we expect to receive
const { displayDetails } = req.body;
//We check that we receive displayDetails and it must be a bool.
if (typeof displayDetails != 'boolean') {
//If a variable is empty.
res.status(422).json({
message: 'Unexpected data',
});
//A return to make sure we don't go any further if data are incorrect.
return;
}
try {
//console.log('API call (PUT)');
//Find the absolute path of the json directory
const jsonDirectory = path.join(process.cwd(), '/config');
let repoList = await fs.readFile(
jsonDirectory + '/repo.json',
'utf8'
);
//Parse the repoList
repoList = JSON.parse(repoList);
//Find the ID in the data and change the values transmitted by the form
let newRepoList = repoList.map((repo) =>
repo.id == req.query.slug
? {
...repo,
displayDetails: displayDetails,
}
: repo
);
//Stringify the newRepoList to write it into the json file.
newRepoList = JSON.stringify(newRepoList);
//Write the new json
await fs.writeFile(
jsonDirectory + '/repo.json',
newRepoList,
(err) => {
if (err) console.log(err);
}
);
res.status(200).json({ message: 'Envoi API réussi' });
} catch (error) {
//Log for backend
console.log(error);
//Log for frontend
if (error.code == 'ENOENT') {
res.status(500).json({
status: 500,
message: 'No such file or directory',
});
} else {
res.status(500).json({
status: 500,
message: 'API error, contact the administrator',
});
}
return;
}
} else {
res.status(405).json({
status: 405,
message: 'Method Not Allowed ',
});
}
}