* add segment model * add note model * db handle segment & note * add notes & segments handler * refactor media caption components * segment & note create * fix type * update note column & may sync * display selected words for note * refactor selected words * auto select words when editing note * refactor * refactor caption component * display notes * refactor notes components * fix * refactor segment & notes into context * destroy note * update locale * fix caption switch issue * fix layout * refactor caption layout * remove deprecated code * may share note * improve UI * fix notes list auto update after created * remove console.log * add notes page * refactor note parameters * refactor components * mark note on transcription * handle no notes * improve style * improve style * show context menu on selection text * fix utils
89 lines
2.5 KiB
TypeScript
89 lines
2.5 KiB
TypeScript
import { ChevronLeftIcon } from "lucide-react";
|
|
import { Button, toast } from "../components/ui";
|
|
import { t } from "i18next";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { useContext, useEffect, useState } from "react";
|
|
import { AppSettingsProviderContext } from "../context";
|
|
import { NoteSegmentGroup } from "../components";
|
|
|
|
export default function Notes() {
|
|
const navigate = useNavigate();
|
|
|
|
const [groups, setGroups] = useState<
|
|
{
|
|
targetId: string;
|
|
targetType: string;
|
|
count: number;
|
|
segment?: SegmentType;
|
|
}[]
|
|
>([]);
|
|
const [hasMore, setHasMore] = useState<boolean>(true);
|
|
const { EnjoyApp } = useContext(AppSettingsProviderContext);
|
|
|
|
const findNotesGroup = (params?: { offset: number; limit?: number }) => {
|
|
const { offset = 0, limit = 5 } = params || {};
|
|
if (offset > 0 && !hasMore) return;
|
|
|
|
EnjoyApp.notes
|
|
.groupByTarget({
|
|
limit,
|
|
offset,
|
|
})
|
|
.then((noteGroups) => {
|
|
if (offset === 0) {
|
|
setGroups(noteGroups);
|
|
} else {
|
|
setGroups([...groups, ...noteGroups]);
|
|
}
|
|
setHasMore(groups.length === limit);
|
|
})
|
|
.catch((err) => {
|
|
toast.error(err.message);
|
|
});
|
|
};
|
|
|
|
useEffect(() => {
|
|
findNotesGroup({ offset: 0 });
|
|
}, []);
|
|
|
|
return (
|
|
<div className="min-h-[100vh] w-full max-w-5xl mx-auto px-4 py-6 lg:px-8">
|
|
<div className="w-full max-w-screen-md mx-auto">
|
|
<div className="flex space-x-1 items-center mb-4">
|
|
<Button variant="ghost" size="icon" onClick={() => navigate(-1)}>
|
|
<ChevronLeftIcon className="w-5 h-5" />
|
|
</Button>
|
|
<span>{t("sidebar.notes")}</span>
|
|
</div>
|
|
|
|
{groups.length === 0 && (
|
|
<div className="flex justify-center">
|
|
<div className="my-4 text-muted-foreground text-sm">{t("noNotesYet")}</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex flex-col space-y-4">
|
|
{groups.map((group) => (
|
|
<NoteSegmentGroup
|
|
key={group.targetId}
|
|
count={group.count}
|
|
segment={group.segment}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{hasMore && (
|
|
<div className="flex justify-center mt-4">
|
|
<Button
|
|
variant="secondary"
|
|
onClick={() => findNotesGroup({ offset: groups.length })}
|
|
>
|
|
{t("loadMore")}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|