Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
ledouxm committed Oct 28, 2024
1 parent 2c9463a commit 2e508aa
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 210 deletions.
210 changes: 1 addition & 209 deletions packages/frontend/src/features/InfoForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { useIsFormDisabled } from "./DisabledContext";
import { ServiceInstructeurSelect } from "./ServiceInstructeurSelect";
import { deleteImageFromIdb, getPicturesStore, getToUploadStore, getUploadStatusStore, syncImages } from "./idb";
import Badge from "@codegouvfr/react-dsfr/Badge";
import { UploadImage } from "./upload/UploadImage";

export const InfoForm = () => {
const form = useFormContext<Report>();
Expand Down Expand Up @@ -209,212 +210,3 @@ export const InfoForm = () => {
</Flex>
);
};
const broadcastChannel = new BroadcastChannel("sw-messages");

const UploadImage = ({ reportId }: { reportId: string }) => {
const [statusMap, setStatusMap] = useState<Record<string, string>>({});
const ref = useRef<HTMLInputElement>(null);

const onChange = async (e: ChangeEvent<HTMLInputElement>) => {
const picturesStore = getPicturesStore();
const toUploadStore = getToUploadStore();

const id = v4();
const file = e.target.files?.[0];
if (!file) return;

const buffer = await getArrayBufferFromBlob(file);
await set(id, buffer, picturesStore);
await set(id, reportId, toUploadStore);

await db.tmp_pictures.create({ data: { id, reportId, createdAt: new Date() } });
syncImages();
};

useEffect(() => {
const listener = (event: MessageEvent) => {
console.log("message", event.data);
if (event.data.type === "status") {
console.log("status", event.data.id, event.data.status);
setStatusMap((prev) => ({ ...prev, [event.data.id]: event.data.status }));
}
};

broadcastChannel.addEventListener("message", listener);

return () => broadcastChannel.removeEventListener("message", listener);
}, []);

return (
<>
<Button
type="button"
iconId="ri-add-line"
priority="secondary"
nativeButtonProps={{
type: "button",
onClick: () => ref.current?.click(),
}}
>
Ajouter photo
</Button>
<styled.input ref={ref as any} type="file" accept="image/*" onChange={onChange} display="none" />
<ReportPictures statusMap={statusMap} />
</>
);
};

const ReportStatus = ({ status }: { status: "uploading" | "success" | "error" }) => {
const { color, bgColor, label, icon } = statusData[status];

return (
<Badge
className={css({ display: "flex", alignItems: "center" })}
severity={"info"}
noIcon
small
style={{
backgroundColor: bgColor,
color,
// backgroundColor: colors[status][1],
// color: colors[status][0],
}}
>
<styled.span
className={cx(
icon,
css({ "&::before": { w: "12px !important", h: "12px !important", verticalAlign: "middle !important" } }),
)}
/>
<styled.span ml="4px">{label}</styled.span>
</Badge>
);
};

const statusData = {
uploading: { label: "En cours", bgColor: "#FEE7FC", color: "#855080", icon: "fr-icon-refresh-line" },
success: { label: "Ok", bgColor: "#B8FEC9", color: "#18753C", icon: "fr-icon-success-line" },
error: { label: "Erreur", bgColor: "#FEC9C9", color: "#853C3C", icon: "fr-icon-warning-line" },
};

const ReportPictures = ({ statusMap }: { statusMap: Record<string, string> }) => {
const form = useFormContext<Report>();

const reportId = form.getValues().id;

const tmpPicturesQuery = useLiveQuery(
db.tmp_pictures.liveMany({ where: { reportId }, orderBy: { createdAt: "desc" } }),
);

const picturesQuery = useLiveQuery(
db.pictures.liveMany({
where: { reportId },
orderBy: { createdAt: "desc" },
}),
);

const pictures = mergePictureArrays(tmpPicturesQuery.results ?? [], picturesQuery.results ?? []);

return (
<Flex direction="column" w="100%" my="40px">
<InputGroup>
{/* <Flex gap="16px" direction="column"> */}
<Grid gap="16px" gridTemplateColumns={{ base: "repeat(2, 1fr)", md: "repeat(3, 1fr)", lg: "repeat(4, 1fr)" }}>
{pictures?.map((picture, index) => (
<PictureThumbnail key={picture.id} picture={picture as any} index={index} status={statusMap[picture.id]} />
))}
</Grid>
{/* </Flex> */}
</InputGroup>
</Flex>
);
};

const mergePictureArrays = (a: Tmp_pictures[], b: Pictures[]) => {
const map = new Map<string, Tmp_pictures>();

const sortByDate = (a: Tmp_pictures, b: Tmp_pictures) => {
return new Date(a.createdAt!).getTime() - new Date(b.createdAt!).getTime();
};

for (const item of a) {
map.set(item.id, item);
}

for (const item of b) {
map.set(item.id, item);
}

return Array.from(map.values()).sort(sortByDate);
};

const PictureThumbnail = ({ picture, index, status }: { picture: Pictures; index: number; status?: string }) => {
const deletePictureMutation = useMutation(async () => {
await deleteImageFromIdb(picture.id);
await db.tmp_pictures.delete({ where: { id: picture.id } }).catch(() => {});
await db.pictures.delete({ where: { id: picture.id } }).catch(() => {});

return "ok";
});

const bgUrlQuery = useQuery({
queryKey: ["picture", picture.id, picture.url],
queryFn: async () => {
const buffer = await get(picture.id, getPicturesStore());
if (!buffer) return picture.url;

const blob = new Blob([buffer], { type: "image/png" });

return URL.createObjectURL(blob);
},
refetchOnWindowFocus: false,
});

const idbStatusQuery = useQuery({
queryKey: ["picture-status", picture.id],
queryFn: async () => {
const status = await get(picture.id, getUploadStatusStore());
return status ?? null;
},
enabled: !status,
});

const finalStatus = picture.url ? "success" : status ?? idbStatusQuery.data ?? "uploading";

const bgUrl = bgUrlQuery.data;

return (
<Stack>
{/* <Badge severity={finalStatus === "uploading" ? }></Badge> */}
<ReportStatus status={finalStatus as any} />
<Flex
style={bgUrl ? { backgroundImage: `url(${bgUrl})` } : { backgroundColor: "gray" }}
flexDir="column"
justifyContent="flex-end"
w="180px"
h="170px"
backgroundPositionY="-20px"
backgroundSize="cover"
>
<Flex alignItems="center" border="1px solid #DFDFDF" h="40px" bgColor="white">
<Box flex="1" pl="5px">
{index + 1}
</Box>
<Box onClick={() => deletePictureMutation.mutate()} borderLeft="1px solid #DFDFDF">
<Button type="button" iconId="ri-close-circle-fill" priority="tertiary no outline" />
{/* {finalStatus ? <span>{finalStatus}</span> : null} */}
{/* <styled.i className={fr.cx("fr-icon--md", "fr-icon-close-circle-fill")} /> */}
</Box>
</Flex>
</Flex>
</Stack>
);
};

async function getArrayBufferFromBlob(blob: Blob) {
return new Promise<ArrayBuffer>((resolve, _) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result as ArrayBuffer);
reader.readAsArrayBuffer(blob);
});
}
Loading

0 comments on commit 2e508aa

Please sign in to comment.