add pagy for audios/videos
This commit is contained in:
@@ -2,7 +2,7 @@ import { Link } from "react-router-dom";
|
||||
import { cn } from "@renderer/lib/utils";
|
||||
|
||||
export const AudioCard = (props: {
|
||||
audio: AudioType;
|
||||
audio: Partial<AudioType>;
|
||||
className?: string;
|
||||
}) => {
|
||||
const { audio, className } = props;
|
||||
|
||||
@@ -4,9 +4,11 @@ import {
|
||||
AddMediaButton,
|
||||
AudiosTable,
|
||||
AudioEditForm,
|
||||
LoaderSpin,
|
||||
} from "@renderer/components";
|
||||
import { t } from "i18next";
|
||||
import {
|
||||
Button,
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
@@ -23,6 +25,7 @@ import {
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
useToast,
|
||||
} from "@renderer/components/ui";
|
||||
import {
|
||||
DbProviderContext,
|
||||
@@ -43,28 +46,55 @@ export const AudiosComponent = () => {
|
||||
|
||||
const { addDblistener, removeDbListener } = useContext(DbProviderContext);
|
||||
const { EnjoyApp } = useContext(AppSettingsProviderContext);
|
||||
const [offset, setOffest] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { toast } = useToast();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
fetchResources();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
addDblistener(onAudiosUpdate);
|
||||
fetchResources();
|
||||
fetchAudios();
|
||||
|
||||
return () => {
|
||||
removeDbListener(onAudiosUpdate);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const fetchResources = async () => {
|
||||
const audios = await EnjoyApp.audios.findAll({
|
||||
limit: 10,
|
||||
});
|
||||
if (!audios) return;
|
||||
const fetchAudios = async () => {
|
||||
if (loading) return;
|
||||
if (offset === -1) return;
|
||||
|
||||
dispatchAudios({ type: "set", records: audios });
|
||||
setLoading(true);
|
||||
const limit = 10;
|
||||
EnjoyApp.audios
|
||||
.findAll({
|
||||
offset,
|
||||
limit,
|
||||
})
|
||||
.then((_audios) => {
|
||||
if (_audios.length === 0) {
|
||||
setOffest(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_audios.length < limit) {
|
||||
setOffest(-1);
|
||||
} else {
|
||||
setOffest(offset + _audios.length);
|
||||
}
|
||||
|
||||
dispatchAudios({ type: "append", records: _audios });
|
||||
})
|
||||
.catch((err) => {
|
||||
toast({
|
||||
description: err.message,
|
||||
variant: "destructive",
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const onAudiosUpdate = (event: CustomEvent) => {
|
||||
@@ -79,7 +109,7 @@ export const AudiosComponent = () => {
|
||||
dispatchAudios({ type: "destroy", record });
|
||||
}
|
||||
} else if (model === "Video" && action === "create") {
|
||||
navigate(`/videos/${record.id}`);
|
||||
navigate(`/videos/${record.id}`);
|
||||
} else if (model === "Transcription" && action === "update") {
|
||||
dispatchAudios({
|
||||
type: "update",
|
||||
@@ -93,6 +123,8 @@ export const AudiosComponent = () => {
|
||||
};
|
||||
|
||||
if (audios.length === 0) {
|
||||
if (loading) return <LoaderSpin />;
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center h-48 border border-dashed rounded-lg">
|
||||
<AddMediaButton />
|
||||
@@ -135,6 +167,14 @@ export const AudiosComponent = () => {
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
{offset > -1 && (
|
||||
<div className="flex items-center justify-center my-4">
|
||||
<Button variant="link" onClick={fetchAudios}>
|
||||
{t("loadMore")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Dialog
|
||||
open={!!editing}
|
||||
onOpenChange={(value) => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
VideosTable,
|
||||
VideoEditForm,
|
||||
AddMediaButton,
|
||||
LoaderSpin,
|
||||
} from "@renderer/components";
|
||||
import { t } from "i18next";
|
||||
import {
|
||||
@@ -19,10 +20,12 @@ import {
|
||||
AlertDialogDescription,
|
||||
AlertDialogCancel,
|
||||
AlertDialogAction,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
useToast,
|
||||
} from "@renderer/components/ui";
|
||||
import {
|
||||
DbProviderContext,
|
||||
@@ -43,11 +46,11 @@ export const VideosComponent = () => {
|
||||
|
||||
const { addDblistener, removeDbListener } = useContext(DbProviderContext);
|
||||
const { EnjoyApp } = useContext(AppSettingsProviderContext);
|
||||
const navigate = useNavigate();
|
||||
const [offset, setOffest] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { toast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
fetchVideos();
|
||||
}, []);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
addDblistener(onVideosUpdate);
|
||||
@@ -59,12 +62,39 @@ export const VideosComponent = () => {
|
||||
}, []);
|
||||
|
||||
const fetchVideos = async () => {
|
||||
const videos = await EnjoyApp.videos.findAll({
|
||||
limit: 10,
|
||||
});
|
||||
if (!videos) return;
|
||||
if (loading) return;
|
||||
if (offset === -1) return;
|
||||
|
||||
dispatchVideos({ type: "set", records: videos });
|
||||
setLoading(true);
|
||||
const limit = 10;
|
||||
EnjoyApp.videos
|
||||
.findAll({
|
||||
offset,
|
||||
limit,
|
||||
})
|
||||
.then((_videos) => {
|
||||
if (_videos.length === 0) {
|
||||
setOffest(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_videos.length < limit) {
|
||||
setOffest(-1);
|
||||
} else {
|
||||
setOffest(offset + _videos.length);
|
||||
}
|
||||
|
||||
dispatchVideos({ type: "append", records: _videos });
|
||||
})
|
||||
.catch((err) => {
|
||||
toast({
|
||||
description: err.message,
|
||||
variant: "destructive",
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const onVideosUpdate = (event: CustomEvent) => {
|
||||
@@ -93,6 +123,8 @@ export const VideosComponent = () => {
|
||||
};
|
||||
|
||||
if (videos.length === 0) {
|
||||
if (loading) return <LoaderSpin />;
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center h-48 border border-dashed rounded-lg">
|
||||
<AddMediaButton />
|
||||
@@ -135,6 +167,14 @@ export const VideosComponent = () => {
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
{offset > -1 && (
|
||||
<div className="flex items-center justify-center my-4">
|
||||
<Button variant="link" onClick={fetchVideos}>
|
||||
{t("loadMore")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Dialog
|
||||
open={!!editing}
|
||||
onOpenChange={(value) => {
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
export const audiosReducer = (
|
||||
audios: AudioType[],
|
||||
action: {
|
||||
type: "create" | "update" | "destroy" | "set";
|
||||
type: "append" | "create" | "update" | "destroy" | "set";
|
||||
record?: Partial<AudioType>;
|
||||
records?: Partial<AudioType>[];
|
||||
}
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case "append": {
|
||||
if (action.record) {
|
||||
return [...audios, action.record];
|
||||
} else if (action.records) {
|
||||
return [...audios, ...action.records];
|
||||
}
|
||||
}
|
||||
case "create": {
|
||||
return [action.record, ...audios];
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
export const videosReducer = (
|
||||
videos: VideoType[],
|
||||
action: {
|
||||
type: "create" | "update" | "destroy" | "set";
|
||||
type: "append" | "create" | "update" | "destroy" | "set";
|
||||
record?: Partial<VideoType>;
|
||||
records?: Partial<VideoType>[];
|
||||
}
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case "append": {
|
||||
if (action.record) {
|
||||
return [...videos, action.record];
|
||||
} else if (action.records) {
|
||||
return [...videos, ...action.records];
|
||||
}
|
||||
}
|
||||
case "create": {
|
||||
return [action.record, ...videos];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user