Skip to content
This repository was archived by the owner on Mar 24, 2024. It is now read-only.

Commit d96e7d9

Browse files
authored
[Front] Merge PhotoList | MovePhoto onSuccess - [Back] ProductPostMovePhoto (#111)
* Refactor ProductGet and SignalR classes * Update variable names, functions, and log messages for clarity and functionality Renamed `orders` to `photos` in `ProductPostMovePhoto` method in `AdminHub` class for clarity. Updated version numbers in comments across multiple files. Added new `refresh` function in `useSWR` function, replacing previous logic. `AdminProductPhotoAction` function now takes `ProductId` as a prop and updates photo list after a photo is moved. `AdminProductPhoto` function maps data to a new `list` variable used as `Items` prop for `DelegateDataGrid` component. Similar mapping done in `ProductCarousel` function. Changed log message in `PhotoList` method from warning to debug and updated parameters for `useSWR` function in `usePhotoList` method.
1 parent 1ea80c5 commit d96e7d9

File tree

10 files changed

+742
-562
lines changed

10 files changed

+742
-562
lines changed

Diff for: SoarCraft.AwaiShop/AdminHub/Product/Post.cs

+9-12
Original file line numberDiff line numberDiff line change
@@ -38,38 +38,35 @@ public async Task<uint> ProductPostCreate(string name) {
3838
* <remarks>
3939
* @author Aloento
4040
* @since 0.5.0
41-
* @version 0.1.0
41+
* @version 1.0.0
4242
* </remarks>
4343
*/
4444
public async Task<bool> ProductPostMovePhoto(uint photoId, bool up) {
45-
var orders = await this.Db.Photos
45+
var photos = await this.Db.Photos
4646
.Where(x => x.ProductId == this.Db.Photos
4747
.Where(y => y.PhotoId == photoId)
4848
.Select(z => z.ProductId)
4949
.Single())
5050
.OrderBy(x => x.Order)
5151
.ToListAsync();
5252

53-
var index = orders.FindIndex(x => x.PhotoId == photoId);
54-
var current = orders[index].Order;
53+
var index = photos.FindIndex(x => x.PhotoId == photoId);
54+
var current = photos[index].Order;
5555

5656
if (up) {
5757
if (current == 1)
5858
throw new HubException("Photo already at top");
5959

60-
orders[index - 1].Order = current;
61-
orders[index].Order = (byte)(current - 1);
60+
photos[index - 1].Order = current;
61+
photos[index].Order = (byte)(current - 1);
6262
} else {
63-
if (current == orders.Last().Order)
63+
if (current == photos.Last().Order)
6464
throw new HubException("Photo already at bottom");
6565

66-
orders[index + 1].Order = current;
67-
orders[index].Order = (byte)(current + 1);
66+
photos[index + 1].Order = current;
67+
photos[index].Order = (byte)(current + 1);
6868
}
6969

70-
for (byte i = 0; i < orders.Count; i++)
71-
orders[i].Order = (byte)(i + 1);
72-
7370
await this.Db.SaveChangesAsync();
7471
return true;
7572
}

Diff for: SoarCraft.AwaiShop/SoarCraft.AwaiShop.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@
3939
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
4040
</PackageReference>
4141
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
42-
<PackageReference Include="Microsoft.Identity.Web" Version="2.17.0" />
42+
<PackageReference Include="Microsoft.Identity.Web" Version="2.17.1" />
4343
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
4444
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.2" />
45-
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="8.102.1" />
45+
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="8.102.1.1" />
4646
</ItemGroup>
4747

4848
<ItemGroup>

Diff for: package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"@azure/msal-browser": "^3.10.0",
1919
"@azure/msal-common": "^14.7.1",
2020
"@azure/msal-react": "^2.0.12",
21-
"@fluentui/react-components": "^9.46.5",
21+
"@fluentui/react-components": "^9.46.6",
2222
"@fluentui/react-hooks": "^8.6.36",
2323
"@fluentui/react-icons": "^2.0.230",
2424
"@griffel/react": "^1.5.20",
@@ -53,7 +53,7 @@
5353
},
5454
"devDependencies": {
5555
"@types/lodash-es": "^4.17.12",
56-
"@types/react": "^18.2.58",
56+
"@types/react": "^18.2.60",
5757
"@types/react-dom": "^18.2.19",
5858
"@vitejs/plugin-react-swc": "^3.6.0",
5959
"typescript": "^5.3.3",

Diff for: pnpm-lock.yaml

+663-490
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/Helpers/useSWR.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Options, Service } from "ahooks/lib/useRequest/src/types";
44
/**
55
* @author Aloento
66
* @since 1.3.5
7-
* @version 0.3.0
7+
* @version 0.4.0
88
*/
99
export function useSWR<TData, TParams extends any[]>(
1010
key: string,
@@ -27,15 +27,15 @@ export function useSWR<TData, TParams extends any[]>(
2727
}
2828
);
2929

30+
function refresh() {
31+
clearCache(key);
32+
localStorage.removeItem(key);
33+
return req.refreshAsync();
34+
}
35+
3036
return {
3137
...req,
32-
refresh: () => {
33-
if (options.useMemory)
34-
clearCache(key);
35-
else
36-
localStorage.removeItem(key);
37-
38-
req.refresh();
39-
}
38+
refresh,
39+
refreshAsync: refresh,
4040
};
4141
}

Diff for: src/Pages/Admin/Product/Photo/Action.tsx

+23-3
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@ import { Button } from "@fluentui/react-components";
22
import { ArrowDownRegular, ArrowUpRegular } from "@fluentui/react-icons";
33
import { ICompLog } from "~/Helpers/Logger";
44
import { useErrorToast } from "~/Helpers/useToast";
5+
import { Hub } from "~/ShopNet";
56
import { AdminHub } from "~/ShopNet/Admin";
67
import { IPhotoItem } from ".";
78
import { AdminProductPhotoEdit } from "./Edit";
89

910
/**
1011
* @author Aloento
1112
* @since 1.4.0
12-
* @version 0.1.0
13+
* @version 0.2.0
1314
*/
1415
export function AdminProductPhotoAction(props: IPhotoItem & ICompLog) {
15-
const { Id, ParentLog } = props;
16+
const { Id, ProductId, ParentLog } = props;
1617
const { dispatch } = useErrorToast(ParentLog);
1718

19+
const { mutate } = Hub.Product.Get.usePhotoList(ProductId, ParentLog);
20+
1821
const { run } = AdminHub.Product.Post.useMovePhoto({
1922
manual: true,
2023
onError(e, params) {
@@ -23,7 +26,24 @@ export function AdminProductPhotoAction(props: IPhotoItem & ICompLog) {
2326
Request: params,
2427
Error: e
2528
});
26-
}
29+
},
30+
onSuccess: (_, [__, up]) => mutate(old => {
31+
const list = old![0];
32+
33+
const index = list.findIndex(x => x.PhotoId === Id);
34+
if (index === -1)
35+
return old;
36+
37+
const newIndex = up ? index - 1 : index + 1;
38+
if (newIndex < 0 || newIndex >= list.length)
39+
return old;
40+
41+
const temp = list[index];
42+
list[index] = list[newIndex];
43+
list[newIndex] = temp;
44+
45+
return old;
46+
})
2747
});
2848

2949
return <>

Diff for: src/Pages/Admin/Product/Photo/index.tsx

+10-9
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,15 @@ const columns: TableColumnDefinition<IPhotoItem>[] = [
8282
* @version 1.0.0
8383
*/
8484
export function AdminProductPhoto({ ProdId }: { ProdId: number }) {
85-
const { data: [list] } = Hub.Product.Get.usePhotoList(ProdId, log);
85+
const { data } = Hub.Product.Get.usePhotoList(ProdId, log);
86+
const list = data
87+
? data[0].map(x => ({
88+
Id: x.PhotoId,
89+
Cover: x.ObjectId,
90+
Caption: x.Caption,
91+
ProductId: x.ProductId
92+
}))
93+
: undefined;
8694

8795
const { dispatch, dispatchToast } = useErrorToast(log);
8896

@@ -137,14 +145,7 @@ export function AdminProductPhoto({ ProdId }: { ProdId: number }) {
137145
</div>
138146

139147
<DelegateDataGrid
140-
Items={
141-
list?.map(x => ({
142-
Id: x.PhotoId,
143-
Cover: x.ObjectId,
144-
Caption: x.Caption,
145-
ProductId: x.ProductId
146-
}))
147-
}
148+
Items={list}
148149
Columns={columns}
149150
/>
150151
</>

Diff for: src/Pages/Product/Carousel.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ export function ProductCarousel({ Id }: { Id: number; }) {
3333
const style = useStyles();
3434
const [imgs, setImgs] = useState<[string, string?][]>([[img]]);
3535

36-
const { data: [list] } = Hub.Product.Get.usePhotoList(Id, log);
36+
const { data } = Hub.Product.Get.usePhotoList(Id, log);
37+
const list = data ? data[0] : undefined;
3738

3839
useAsyncEffect(async () => {
3940
if (!list) return;

Diff for: src/ShopNet/Product/Get.ts

+20-32
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import { useConst } from "@fluentui/react-hooks";
2-
import { useAsyncEffect } from "ahooks";
3-
import { useState } from "react";
41
import type { Logger } from "~/Helpers/Logger";
2+
import { useSWR } from "~/Helpers/useSWR";
53
import { IComboItem } from "~/Pages/Admin/Product/Combo";
64
import type { IGallery } from "~/Pages/Gallery";
75
import { ProductData } from "./Data";
@@ -115,13 +113,16 @@ export abstract class ProductGet extends ProductData {
115113
* @liveSafe
116114
* @deprecated Use {@link usePhotoList} if possible.
117115
*/
118-
public static async PhotoList(prodId: number, pLog: Logger) {
116+
public static async PhotoList(prodId: number, pLog: Logger): Promise<[ProductData.Photo[], string]> {
119117
const log = pLog.With(...this.Log, "PhotoList");
120-
const ids = await this.GetTimeCache<number[]>(prodId, this.photoList, (x) => x, prodId).catch(log.error);
121-
return this.makePhotoList(prodId, ids || [], log);
122-
}
123118

124-
private static async makePhotoList(prodId: number, ids: number[], log: Logger): Promise<[ProductData.Photo[], string]> {
119+
const index = this.Index(prodId, this.photoList);
120+
await this.getLocker(index);
121+
this.reqPool.add(index);
122+
123+
const ids = await this.Invoke<number[]>(this.photoList, prodId)
124+
.finally(() => this.reqPool.delete(index));
125+
125126
let list = [];
126127
let cover = "";
127128

@@ -140,7 +141,7 @@ export abstract class ProductGet extends ProductData {
140141
list = list.sort((a, b) => a.Order - b.Order);
141142

142143
if (!cover && list.length > 0) {
143-
log.warn(`Product ${prodId} has no cover photo, using first photo instead`);
144+
log.debug(`Product ${prodId} has no cover photo, using first photo instead`);
144145
return [list, list[0].ObjectId];
145146
}
146147

@@ -150,31 +151,18 @@ export abstract class ProductGet extends ProductData {
150151
/**
151152
* @author Aloento
152153
* @since 1.4.0
153-
* @version 0.1.0
154+
* @version 0.2.0
154155
*/
155156
public static usePhotoList(prodId: number, pLog: Logger) {
156-
const log = useConst(() => pLog.With(...this.Log, "PhotoList"));
157-
const [list, setList] = useState<ProductData.Photo[]>();
158-
const [cover, setCover] = useState<string>();
159-
160-
const req = this.useTimeCache<number[]>(prodId, this.photoList, {
161-
defaultParams: [prodId],
162-
onError: log.error,
163-
});
164-
165-
useAsyncEffect(async () => {
166-
const ids = req.data;
167-
if (!ids)
168-
return;
169-
170-
const [list, cover] = await this.makePhotoList(prodId, ids, log);
171-
setList(list);
172-
setCover(cover);
173-
}, [req.data]);
157+
const req = useSWR(
158+
this.Index(prodId, this.photoList),
159+
(id) => this.PhotoList(id, pLog),
160+
{
161+
defaultParams: [prodId],
162+
onError: pLog.error
163+
}
164+
);
174165

175-
return {
176-
...req,
177-
data: [list, cover] as const
178-
}
166+
return req;
179167
}
180168
}

Diff for: src/ShopNet/SignalR.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,14 @@ export abstract class SignalR {
120120
* @since 1.3.5
121121
* @version 0.1.0
122122
*/
123-
private static readonly reqPool = new Set<string>();
123+
protected static readonly reqPool = new Set<string>();
124124

125125
/**
126126
* @author Aloento
127127
* @since 1.3.5
128128
* @version 0.1.0
129129
*/
130-
private static async getLocker(key: string) {
130+
protected static async getLocker(key: string) {
131131
if (this.reqPool.has(key))
132132
return new Promise<void>(res => {
133133
const t = setTimeout(() => this.reqPool.delete(key), 10000);

0 commit comments

Comments
 (0)