💄 Améliore l'affichage et certaines actions
Fait fonctionner la suppression d'une page Fait fonctionner la pagination Fait fonctionner mieux le formulaire Fait fonctionner le markdown
This commit is contained in:
parent
a8116aa5a2
commit
844f625298
77744
public/js/app.js
vendored
77744
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@ import PageForm from "./Form";
|
|||||||
import Pages from "./List";
|
import Pages from "./List";
|
||||||
import Prompt from "./Prompt";
|
import Prompt from "./Prompt";
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {Alert, AlertTitle, Divider} from "@mui/material";
|
import {Alert, AlertTitle, Button, Divider} from "@mui/material";
|
||||||
import {EncryptStorage} from "storage-encryption";
|
import {EncryptStorage} from "storage-encryption";
|
||||||
import {
|
import {
|
||||||
Switch,
|
Switch,
|
||||||
@ -96,17 +96,18 @@ function App() {
|
|||||||
|
|
||||||
return user ? (
|
return user ? (
|
||||||
<p>
|
<p>
|
||||||
Welcome!{" "}
|
Bienvenue !{" "}
|
||||||
<button
|
<Button variant="outlined" size="small" sx={{align: "right"}} onClick={() => {
|
||||||
onClick={() => {
|
signout(() => history.push("/"));
|
||||||
signout(() => history.push("/"));
|
}}>
|
||||||
}}
|
Fermer mon carnet Ă clef
|
||||||
>
|
</Button>
|
||||||
Sign out
|
|
||||||
</button>
|
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p>You are not logged in.</p>
|
<p>
|
||||||
|
Votre carnet est fermé.{" "}
|
||||||
|
<Link to="/diary/public/pages">Voir vos pages</Link>
|
||||||
|
</p>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ function App() {
|
|||||||
|
|
||||||
function ListPage() {
|
function ListPage() {
|
||||||
return (
|
return (
|
||||||
<div className="col-md-8">
|
<div className="col-md-12">
|
||||||
<Pages
|
<Pages
|
||||||
pages={listPages}
|
pages={listPages}
|
||||||
url={getPageContentUrl}
|
url={getPageContentUrl}
|
||||||
@ -167,12 +168,7 @@ function App() {
|
|||||||
<div>
|
<div>
|
||||||
<AuthButton />
|
<AuthButton />
|
||||||
<Error/>
|
<Error/>
|
||||||
<ul>
|
<Divider sx={{height: "20px", mb: "20px", mt:"10px"}}/>
|
||||||
<li>
|
|
||||||
<Link to="/diary/public/pages">Voir vos pages</Link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/diary/public/pass">
|
<Route path="/diary/public/pass">
|
||||||
<PromptPage />
|
<PromptPage />
|
||||||
|
@ -6,31 +6,35 @@ let encryptStorage = new EncryptStorage('test'); // TODO la clef doit venir de l
|
|||||||
|
|
||||||
export default function PageForm({setListPages, csrf, url, passphrase}) {
|
export default function PageForm({setListPages, csrf, url, passphrase}) {
|
||||||
const isPassphraseSet = passphrase !== null;
|
const isPassphraseSet = passphrase !== null;
|
||||||
|
const [content, setContent] = React.useState("");
|
||||||
const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
encryptStorage = new EncryptStorage(passphrase);
|
encryptStorage = new EncryptStorage(passphrase);
|
||||||
let HTMLForm : HTMLFormElement = event.currentTarget;
|
const HTMLForm : HTMLFormElement = event.currentTarget;
|
||||||
let decryptedFormData = new FormData(HTMLForm);
|
const decryptedFormData = new FormData(HTMLForm);
|
||||||
let encryptedFormData = new FormData();
|
const encryptedFormData = new FormData();
|
||||||
for (let [key, value] of decryptedFormData.entries()) {
|
for (const [key, value] of decryptedFormData.entries()) {
|
||||||
encryptStorage.encrypt('uuid'+key, value);
|
encryptStorage.encrypt('uuid'+key, value);
|
||||||
let newEncryptedString = localStorage.getItem('uuid'+key);
|
const newEncryptedString = localStorage.getItem('uuid'+key);
|
||||||
if (newEncryptedString) {
|
if (newEncryptedString) {
|
||||||
encryptedFormData.append(key, newEncryptedString);
|
encryptedFormData.append(key, newEncryptedString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encryptStorage.encrypt('uuidtext', content);
|
||||||
|
encryptedFormData.append("text", ""+localStorage.getItem('uuidtext'))
|
||||||
|
|
||||||
encryptedFormData.append('_token', csrf);
|
encryptedFormData.append('_token', csrf);
|
||||||
|
|
||||||
let response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: encryptedFormData
|
body: encryptedFormData
|
||||||
});
|
});
|
||||||
|
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
const uuid = json.uuid;
|
const uuid = json.uuid;
|
||||||
for (let key of decryptedFormData.keys()) {
|
for (const key of decryptedFormData.keys()) {
|
||||||
let newEncryptedString = localStorage.getItem('uuid'+key);
|
const newEncryptedString = localStorage.getItem('uuid'+key);
|
||||||
localStorage.setItem(uuid+key, ""+newEncryptedString);
|
localStorage.setItem(uuid+key, ""+newEncryptedString);
|
||||||
localStorage.removeItem("uuid"+key);
|
localStorage.removeItem("uuid"+key);
|
||||||
}
|
}
|
||||||
@ -50,14 +54,10 @@ export default function PageForm({setListPages, csrf, url, passphrase}) {
|
|||||||
|
|
||||||
if (isPassphraseSet) {
|
if (isPassphraseSet) {
|
||||||
return (
|
return (
|
||||||
/* <Stack
|
<form action={url} id="postPage" method="post" onSubmit={onSubmit}>
|
||||||
component="form"
|
<Stack
|
||||||
sx={{
|
component="div"
|
||||||
width: '25ch',
|
|
||||||
}}
|
|
||||||
spacing={2}
|
spacing={2}
|
||||||
noValidate
|
|
||||||
autoComplete="off"
|
|
||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
label="Titre"
|
label="Titre"
|
||||||
@ -67,40 +67,14 @@ export default function PageForm({setListPages, csrf, url, passphrase}) {
|
|||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
<MDEditor
|
<MDEditor
|
||||||
value={value}
|
value={content}
|
||||||
onChange={setValue}
|
onChange={setContent}
|
||||||
/>
|
/>
|
||||||
<MDEditor.Markdown source={value} />
|
<Button variant="contained" type={"submit"}>
|
||||||
<TextField
|
|
||||||
label="Texte"
|
|
||||||
name="content"
|
|
||||||
id="filled-hidden-label-normal"
|
|
||||||
defaultValue="Normal"
|
|
||||||
variant="outlined"
|
|
||||||
multiline
|
|
||||||
maxRows={15}
|
|
||||||
/>
|
|
||||||
<Button variant="contained" component="span" onClick={onSubmit}>
|
|
||||||
Enregistrer
|
Enregistrer
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>*/
|
</Stack>
|
||||||
<div className="container">
|
</form>
|
||||||
<div className="row justify-content-center">
|
|
||||||
<div className="col-md-8">
|
|
||||||
<div className="card">
|
|
||||||
<form action={url} id="postPage" method="post" onSubmit={onSubmit}>
|
|
||||||
<label htmlFor="title">Titre:</label>
|
|
||||||
<input id="title" name="title"/>
|
|
||||||
<hr/>
|
|
||||||
<label htmlFor="text">Texte:</label>
|
|
||||||
<textarea id="text" name="text"/>
|
|
||||||
<hr/>
|
|
||||||
<input type="submit" value="Enregistrer"/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {Grid, List, Pagination} from '@mui/material';
|
import {Grid, Pagination} from '@mui/material';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Page from "./Page";
|
import Page from "./Page";
|
||||||
|
|
||||||
@ -9,18 +9,53 @@ interface List {
|
|||||||
|
|
||||||
export default function Pages({pages, url, removeUrl, csrf, passphrase, setPassphrase}) {
|
export default function Pages({pages, url, removeUrl, csrf, passphrase, setPassphrase}) {
|
||||||
const isPassphraseSet = passphrase !== null;
|
const isPassphraseSet = passphrase !== null;
|
||||||
|
const perPage = 3;
|
||||||
|
const total = pages.length;
|
||||||
|
const numberOfPage = Math.ceil(total/perPage);
|
||||||
|
const [currentPage, setPage] = React.useState(1);
|
||||||
|
const [listPages, setListPages] = React.useState(pages);
|
||||||
|
|
||||||
let listPages = pages.map(page =>
|
const removePage = async (id) => {
|
||||||
<Page page={page} url={url} setPassphrase={setPassphrase} passphrase={passphrase} csrf={csrf} removeUrl={removeUrl} key={page.id}/>
|
const formData = new FormData();
|
||||||
)
|
formData.set('_token', csrf);
|
||||||
|
formData.set('_method', 'DELETE');
|
||||||
|
const response = await fetch(removeUrl.replace("replace_me", id), {
|
||||||
|
method: 'POST', body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
const json = await response.json();
|
||||||
|
|
||||||
|
if (json.success) {
|
||||||
|
console.log(listPages.length);
|
||||||
|
const newListPages = listPages.filter(function (value) {
|
||||||
|
console.log(value.id);
|
||||||
|
return value.id !== id;
|
||||||
|
});
|
||||||
|
setListPages(newListPages);
|
||||||
|
console.log(newListPages.length);
|
||||||
|
console.log(listPages.length);
|
||||||
|
updateListPages(newListPages.slice((currentPage - 1) * perPage, ((currentPage - 1) * perPage) + perPage).map(page =>
|
||||||
|
<Page page={page} url={url} remove={removePage} setPassphrase={setPassphrase} passphrase={passphrase}
|
||||||
|
key={page.id}/>));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [listPagesDisplayed, updateListPages] = React.useState(listPages.slice((currentPage-1) * perPage, ((currentPage-1) * perPage) + perPage ).map(page =>
|
||||||
|
<Page page={page} url={url} remove={removePage} setPassphrase={setPassphrase} passphrase={passphrase} key={page.id}/>));
|
||||||
|
|
||||||
|
const handlePageChange = (event: React.ChangeEvent<unknown>, value: number) => {
|
||||||
|
setPage(value);
|
||||||
|
updateListPages(listPages.slice((value-1) * perPage, ((value-1) * perPage) + perPage).map(page =>
|
||||||
|
<Page page={page} url={url} remove={removePage} setPassphrase={setPassphrase} passphrase={passphrase} key={page.id}/>));
|
||||||
|
};
|
||||||
|
|
||||||
if (isPassphraseSet) {
|
if (isPassphraseSet) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Grid container rowSpacing={1} columnSpacing={1}>
|
<Grid container rowSpacing={1} columnSpacing={1}>
|
||||||
{listPages}
|
{listPagesDisplayed}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Pagination count={10} color="primary" />
|
<Pagination count={numberOfPage} page={currentPage} onChange={handlePageChange} sx={{align: "center"}} color="primary" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {EncryptStorage} from 'storage-encryption';
|
import {EncryptStorage} from 'storage-encryption';
|
||||||
import {Delete} from "@mui/icons-material";
|
import {Delete} from "@mui/icons-material";
|
||||||
import {unmountComponentAtNode} from "react-dom";
|
import MDEditor from "@uiw/react-md-editor";
|
||||||
|
|
||||||
interface Page {
|
interface Page {
|
||||||
date: string;
|
date: string;
|
||||||
@ -36,24 +36,13 @@ const ExpandMore = styled((props: ExpandMoreProps) => {
|
|||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default function Page({page, url, removeUrl, csrf, passphrase, setPassphrase}) {
|
export default function Page({page, url, passphrase, setPassphrase, remove}) {
|
||||||
const [more, setMore] = React.useState(false);
|
const [more, setMore] = React.useState(false);
|
||||||
const [expanded, setExpanded] = React.useState(false);
|
const [expanded, setExpanded] = React.useState(false);
|
||||||
const handleMoreClick = () => { setMore(!more); };
|
const handleMoreClick = () => { setMore(!more); };
|
||||||
const handleExpandClick = () => { onLoad().then(r => setExpanded(!expanded)); };
|
const handleExpandClick = () => { onLoad().then(r => setExpanded(!expanded)); };
|
||||||
const remove = async () => {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.set('_token', csrf);
|
|
||||||
formData.set('_method', 'DELETE');
|
|
||||||
let response = await fetch(removeUrl.replace("replace_me", page.id), {
|
|
||||||
method: 'POST', body: formData
|
|
||||||
});
|
|
||||||
|
|
||||||
const json = await response.json();
|
const encryptStorage = new EncryptStorage(passphrase);
|
||||||
unmountComponentAtNode(document.getElementById(page.id));
|
|
||||||
};
|
|
||||||
|
|
||||||
let encryptStorage = new EncryptStorage(passphrase);
|
|
||||||
let title, content = "";
|
let title, content = "";
|
||||||
let alert_popup:JSX.Element|null = null;
|
let alert_popup:JSX.Element|null = null;
|
||||||
let setTitle, setContent: React.Dispatch<any>|null = null;
|
let setTitle, setContent: React.Dispatch<any>|null = null;
|
||||||
@ -63,9 +52,9 @@ export default function Page({page, url, removeUrl, csrf, passphrase, setPassphr
|
|||||||
[title, setTitle] = React.useState(encryptStorage.decrypt(page.id + "title"));
|
[title, setTitle] = React.useState(encryptStorage.decrypt(page.id + "title"));
|
||||||
onLoad = async () => {
|
onLoad = async () => {
|
||||||
if (localStorage.getItem(page.id + "text") === null) {
|
if (localStorage.getItem(page.id + "text") === null) {
|
||||||
let response = await fetch(url.replace("replace_me", page.id));
|
const response = await fetch(url.replace("replace_me", page.id));
|
||||||
|
|
||||||
let json = await response.json();
|
const json = await response.json();
|
||||||
localStorage.setItem(page.id + "title", json.metadata.title);
|
localStorage.setItem(page.id + "title", json.metadata.title);
|
||||||
localStorage.setItem(page.id + "text", json.content);
|
localStorage.setItem(page.id + "text", json.content);
|
||||||
}
|
}
|
||||||
@ -83,7 +72,7 @@ export default function Page({page, url, removeUrl, csrf, passphrase, setPassphr
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid item xs={12} sm={6} md={6} id={page.id}>
|
<Grid item xs={12} sm={12} md={12} id={page.id}>
|
||||||
{alert_popup}
|
{alert_popup}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader
|
<CardHeader
|
||||||
@ -96,7 +85,7 @@ export default function Page({page, url, removeUrl, csrf, passphrase, setPassphr
|
|||||||
subheader={page.date}
|
subheader={page.date}
|
||||||
/>
|
/>
|
||||||
<Collapse in={more} timeout="auto" unmountOnExit>
|
<Collapse in={more} timeout="auto" unmountOnExit>
|
||||||
<IconButton aria-label="remove" onClick={remove} >
|
<IconButton aria-label="remove" onClick={() => {remove(page.id)}} >
|
||||||
<Delete />
|
<Delete />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
@ -113,7 +102,7 @@ export default function Page({page, url, removeUrl, csrf, passphrase, setPassphr
|
|||||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Typography paragraph>
|
<Typography paragraph>
|
||||||
{content}
|
<MDEditor.Markdown source={content} />
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
Loading…
Reference in New Issue
Block a user