Skip to content

Commit

Permalink
Refactor to redux toolkit
Browse files Browse the repository at this point in the history
  • Loading branch information
derneuere committed Mar 13, 2024
1 parent 7900b91 commit f9c8f0a
Show file tree
Hide file tree
Showing 12 changed files with 283 additions and 317 deletions.
94 changes: 0 additions & 94 deletions src/actions/albumsActions.ts

This file was deleted.

83 changes: 63 additions & 20 deletions src/api_client/albums/date.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FetchDateAlbumResponseSchema, FetchDateAlbumsListResponseSchema } from "../../actions/albumActions.types";
import { IncompleteDatePhotosGroup } from "../../actions/photosActions.types";
import { PhotosetType } from "../../reducers/photosReducer";
import { addTempElementsToGroups } from "../../util/util";
import { api } from "../api";

Expand All @@ -8,40 +9,82 @@ enum Endpoints {
fetchDateAlbum = "fetchDateAlbum",
}

type AlbumDateListOptions = {
photosetType: PhotosetType;
person_id?: number;
username?: string;
};

type AlbumDateOption = {
photosetType: PhotosetType;
album_date_id: string;
page: number;
username?: string;
person_id?: number;
};

export const dateAlbumsApi = api
.injectEndpoints({
endpoints: builder => ({
[Endpoints.fetchDateAlbums]: builder.query<IncompleteDatePhotosGroup[], void>({
query: () => "albums/date/list/",
[Endpoints.fetchDateAlbums]: builder.query<IncompleteDatePhotosGroup[], AlbumDateListOptions>({
query: options => ({
url: "albums/date/list/",
params: {
favorite: PhotosetType.FAVORITES === options.photosetType ? "true" : undefined,
public: PhotosetType.PUBLIC === options.photosetType ? "true" : undefined,
hidden: PhotosetType.HIDDEN === options.photosetType ? "true" : undefined,
deleted: PhotosetType.DELETED === options.photosetType ? "true" : undefined,
photo: PhotosetType.PHOTOS === options.photosetType ? "true" : undefined,
video: PhotosetType.VIDEOS === options.photosetType ? "true" : undefined,
person: options.person_id,
username: options.username?.toLowerCase(),
},
}),
transformResponse: response => {
const { results } = FetchDateAlbumsListResponseSchema.parse(response);
addTempElementsToGroups(results);

return results;
},
}),
[Endpoints.fetchDateAlbum]: builder.query<IncompleteDatePhotosGroup, { id: string; page: number }>({
query: ({ id, page }) => `albums/date/${id}/?page=${page}`,
[Endpoints.fetchDateAlbum]: builder.query<IncompleteDatePhotosGroup, AlbumDateOption>({
query: options => ({
url: `albums/date/${options.album_date_id}`,
params: {
favorite: PhotosetType.FAVORITES === options.photosetType ? "true" : undefined,
public: PhotosetType.PUBLIC === options.photosetType ? "true" : undefined,
hidden: PhotosetType.HIDDEN === options.photosetType ? "true" : undefined,
deleted: PhotosetType.DELETED === options.photosetType ? "true" : undefined,
photo: PhotosetType.PHOTOS === options.photosetType ? "true" : undefined,
video: PhotosetType.VIDEOS === options.photosetType ? "true" : undefined,
page: options.page,
person: options.person_id,
username: options.username?.toLowerCase(),
},
}),
transformResponse: response => FetchDateAlbumResponseSchema.parse(response).results,
// Add results to fetchDateAlbums cache
async onQueryStarted({ id, page }, { dispatch, queryFulfilled }) {
async onQueryStarted(options, { dispatch, queryFulfilled }) {
const { data } = await queryFulfilled;

dispatch(
dateAlbumsApi.util.updateQueryData(Endpoints.fetchDateAlbums, undefined, draft => {
const indexToReplace = draft.findIndex(group => group.id === id);
const groupToChange = draft[indexToReplace];
if (!groupToChange) return;

const { items } = groupToChange;
groupToChange.items = items
.slice(0, (page - 1) * 100)
.concat(data.items)
.concat(items.slice(page * 100));

// eslint-disable-next-line no-param-reassign
draft[indexToReplace] = groupToChange;
})
dateAlbumsApi.util.updateQueryData(
Endpoints.fetchDateAlbums,
{ photosetType: options.photosetType, person_id: options.person_id, username: options.username },
draft => {
const indexToReplace = draft.findIndex(group => group.id === options.album_date_id);
const groupToChange = draft[indexToReplace];
if (!groupToChange) return;

const { items } = groupToChange;
groupToChange.items = items
.slice(0, (options.page - 1) * 100)
.concat(data.items)
.concat(items.slice(options.page * 100));

// eslint-disable-next-line no-param-reassign
draft[indexToReplace] = groupToChange;
}
)
);
},
}),
Expand Down
14 changes: 8 additions & 6 deletions src/hooks/useWorkerStatus.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";

import { fetchAlbumDateList } from "../actions/albumsActions";
import { dateAlbumsApi } from "../api_client/albums/date";
import { peopleAlbumsApi } from "../api_client/albums/people";
import { api, useWorkerQuery } from "../api_client/api";
import { PhotosetType } from "../reducers/photosReducer";
Expand Down Expand Up @@ -47,11 +47,13 @@ export function useWorkerStatus(): {
dispatch(peopleAlbumsApi.endpoints.fetchPeopleAlbums.initiate());
}
if (workerRunningJob?.job_type_str.toLowerCase() === "scan photos") {
fetchAlbumDateList(dispatch, {
username: user.username,
person_id: user.id,
photosetType: PhotosetType.NONE,
});
dispatch(
dateAlbumsApi.endpoints.fetchDateAlbums.initiate({
username: user.username,
person_id: user.id,
photosetType: PhotosetType.NONE,
})
);
}
}

Expand Down
72 changes: 37 additions & 35 deletions src/layouts/albums/AlbumPersonGallery.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,65 @@
import { IconUser as User } from "@tabler/icons-react";
import _ from "lodash";
import React, { useCallback, useEffect, useState } from "react";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";

import { fetchAlbumDate, fetchAlbumDateList } from "../../actions/albumsActions";
import { PigPhoto } from "../../actions/photosActions.types";
import { useFetchDateAlbumQuery, useFetchDateAlbumsQuery } from "../../api_client/albums/date";
import { useFetchPeopleAlbumsQuery } from "../../api_client/albums/people";
import { PhotoListView } from "../../components/photolist/PhotoListView";
import type { PhotosState } from "../../reducers/photosReducer";
import { PhotosetType } from "../../reducers/photosReducer";
import { useAppDispatch, useAppSelector } from "../../store/store";
import { updatePhotoGroups } from "../photos/common";

type IFetchedGroup = {
id: string;
page: number;
};
import { getPhotosFlatFromGroupedByDate } from "../../util/util";
import type { PhotoGroup } from "../photos/common";

export function AlbumPersonGallery(): JSX.Element {
const { albumID } = useParams();
const { fetchedPhotosetType, photosFlat, photosGroupedByDate } = useAppSelector(state => state.photos as PhotosState);
const { data: people } = useFetchPeopleAlbumsQuery();
const dispatch = useAppDispatch();
const { t } = useTranslation();
const [group, setGroup] = useState({} as IFetchedGroup);
const [photosFlat, setPhotosFlat] = useState<PigPhoto[]>([]);
const { data: people } = useFetchPeopleAlbumsQuery();

const person = people?.filter((i: any) => i.key === albumID)[0];
const personname = person ? person.value : undefined;

useEffect(() => {
if (group.id && group.page) {
fetchAlbumDate(dispatch, {
album_date_id: group.id,
page: group.page,
photosetType: PhotosetType.PERSON,
person_id: albumID ? +albumID : undefined,
});
}
}, [group.id, group.page]);
const { data: photosGroupedByDate, isLoading } = useFetchDateAlbumsQuery({
photosetType: PhotosetType.PERSON,
person_id: albumID ? +albumID : undefined,
});

useEffect(() => {
fetchAlbumDateList(dispatch, {
if (photosGroupedByDate) setPhotosFlat(getPhotosFlatFromGroupedByDate(photosGroupedByDate));
}, [photosGroupedByDate]);

const [group, setGroup] = useState({} as PhotoGroup);
useFetchDateAlbumQuery(
{
album_date_id: group.id,
page: group.page,
photosetType: PhotosetType.PERSON,
person_id: albumID ? +albumID : undefined,
});
}, [dispatch]); // Only run on first render

const throttledGetAlbums = useCallback(
_.throttle(visibleItems => updatePhotoGroups(setGroup)(visibleItems), 500),
[]
},
{ skip: !group.id }
);

const getAlbums = (visibleGroups: any) => {
visibleGroups.reverse().forEach((photoGroup: any) => {
const visibleImages = photoGroup.items;
if (visibleImages.filter((i: any) => i.isTemp).length > 0) {
const firstTempObject = visibleImages.filter((i: any) => i.isTemp)[0];
const page = Math.ceil((parseInt(firstTempObject.id, 10) + 1) / 100);

setGroup({ id: photoGroup.id, page });
}
});
};

return (
<PhotoListView
title={personname || t("loading")}
loading={fetchedPhotosetType !== PhotosetType.PERSON}
loading={isLoading}
icon={<User size={50} />}
photoset={photosGroupedByDate}
photoset={photosGroupedByDate ?? []}
idx2hash={photosFlat}
updateGroups={throttledGetAlbums}
updateGroups={getAlbums}
selectable
/>
);
Expand Down
Loading

0 comments on commit f9c8f0a

Please sign in to comment.