124 lines
4.5 KiB
TypeScript
124 lines
4.5 KiB
TypeScript
import {
|
|
Alert,
|
|
AlertTitle,
|
|
Card, CardActions,
|
|
CardContent,
|
|
CardHeader, Collapse,
|
|
Grid, IconButton, IconButtonProps,
|
|
Typography
|
|
} from '@mui/material';
|
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
|
import { styled } from '@mui/material/styles';
|
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
import * as React from 'react';
|
|
import {EncryptStorage} from 'storage-encryption';
|
|
import {Delete} from "@mui/icons-material";
|
|
import {unmountComponentAtNode} from "react-dom";
|
|
|
|
interface Page {
|
|
date: string;
|
|
title: string;
|
|
content: string;
|
|
}
|
|
|
|
interface ExpandMoreProps extends IconButtonProps {
|
|
expand: boolean;
|
|
}
|
|
|
|
const ExpandMore = styled((props: ExpandMoreProps) => {
|
|
const { expand, ...other } = props;
|
|
return <IconButton {...other} />;
|
|
})(({ theme, expand }) => ({
|
|
transform: !expand ? 'rotate(0deg)' : 'rotate(180deg)',
|
|
marginLeft: 'auto',
|
|
transition: theme.transitions.create('transform', {
|
|
duration: theme.transitions.duration.shortest,
|
|
}),
|
|
}));
|
|
|
|
export default function Page({page, url, removeUrl, csrf, passphrase, setPassphrase}) {
|
|
const [more, setMore] = React.useState(false);
|
|
const [expanded, setExpanded] = React.useState(false);
|
|
const handleMoreClick = () => { setMore(!more); };
|
|
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();
|
|
unmountComponentAtNode(document.getElementById(page.id));
|
|
};
|
|
|
|
let encryptStorage = new EncryptStorage(passphrase);
|
|
let title, content = "";
|
|
let alert_popup:JSX.Element|null = null;
|
|
let setTitle, setContent: React.Dispatch<any>|null = null;
|
|
let onLoad = async () => {};
|
|
try {
|
|
[content, setContent] = React.useState(encryptStorage.decrypt(page.id + "text"));
|
|
[title, setTitle] = React.useState(encryptStorage.decrypt(page.id + "title"));
|
|
onLoad = async () => {
|
|
if (localStorage.getItem(page.id + "text") === null) {
|
|
let response = await fetch(url.replace("replace_me", page.id));
|
|
|
|
let json = await response.json();
|
|
localStorage.setItem(page.id + "title", json.metadata.title);
|
|
localStorage.setItem(page.id + "text", json.content);
|
|
}
|
|
setTitle(encryptStorage.decrypt(page.id + "title"));
|
|
// @ts-ignore
|
|
setContent(encryptStorage.decrypt(page.id + "text"));
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
setPassphrase(null);
|
|
alert_popup = <Alert severity="error">
|
|
<AlertTitle>Erreur</AlertTitle>
|
|
Vos pages ne peuvent pas être décodées — <strong>Réindiquez votre clef!</strong>
|
|
</Alert>
|
|
}
|
|
|
|
return (
|
|
<Grid item xs={12} sm={6} md={6} id={page.id}>
|
|
{alert_popup}
|
|
<Card>
|
|
<CardHeader
|
|
action={
|
|
<IconButton aria-label="settings">
|
|
<MoreVertIcon onClick={handleMoreClick} />
|
|
</IconButton>
|
|
}
|
|
title={title}
|
|
subheader={page.date}
|
|
/>
|
|
<Collapse in={more} timeout="auto" unmountOnExit>
|
|
<IconButton aria-label="remove">
|
|
<Delete onClick={remove} />
|
|
</IconButton>
|
|
</Collapse>
|
|
<CardActions disableSpacing>
|
|
<ExpandMore
|
|
expand={expanded}
|
|
onClick={handleExpandClick}
|
|
aria-expanded={expanded}
|
|
aria-label="show more"
|
|
>
|
|
<ExpandMoreIcon />
|
|
</ExpandMore>
|
|
</CardActions>
|
|
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
|
<CardContent>
|
|
<Typography paragraph>
|
|
{content}
|
|
</Typography>
|
|
</CardContent>
|
|
</Collapse>
|
|
</Card>
|
|
</Grid>
|
|
);
|
|
}
|