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

Commit

Permalink
[Back] ProductDetachCategory | ProductPostPhoto | PhotoEntity - [Fron…
Browse files Browse the repository at this point in the history
…t] AdminProductPhotoEdit | AdminProductPhoto (#96)

* The most significant changes revolve around the modification of methods and classes related to product photos in an e-commerce application. The changes aim to improve readability, efficiency, and real-time responsiveness of the application. The changes also allow the application to handle more complex scenarios, better track and manage photos, and improve cache management.

1. `ProductDetachCategory` method in `Delete.cs` has been refactored for improved readability and efficiency. It now checks if the product has a category before removing it and deletes the category if it has no associated products. The method now returns a boolean indicating the success of the operation.

2. `ProductPostPhoto` method in `Post.cs` has been modified to return the ID of the newly added photo instead of a boolean, providing more useful information to the caller.

3. `PhotoEntity` method in `Entity.cs` has been simplified to return a single photo entity based on its ID.

4. `AdminProductPhotoEdit` function in `Edit.tsx` now takes an additional `ProductId` property, allowing it to perform operations related to the product that the photo belongs to.

5. `AdminProductPhoto` function in `index.tsx` now uses the `useLiveQuery` hook from `dexie-react-hooks` to fetch photo data, improving the real-time responsiveness of the application.

6. `usePhoto` methods in `Delete.ts` and `Post.ts` have been updated to take additional parameters and perform additional operations, allowing them to handle more complex scenarios.

7. `Photo` type in `Data.ts` has been updated to include `PhotoId` and `ProductId` properties, allowing the application to better track and manage photos.

8. `PhotoList` method in `Get.ts` has been updated to use a constant for the cache key, and a new `PhotoListUpdate` method has been added, improving the cache management of the application.

* Refactor photo update logic and remove unused code
  • Loading branch information
Aloento authored Jan 25, 2024
1 parent 514e56a commit 1a5fa23
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 80 deletions.
18 changes: 10 additions & 8 deletions SoarCraft.AwaiShop/AdminHub/Product/Delete.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public async Task<bool> ProductDeletePhoto(uint photoId) {
* <summary>
* Include Types -> Combos
* </summary>
*
* <remarks>
* @author Aloento
* @since 0.5.0
Expand Down Expand Up @@ -71,7 +70,6 @@ await this.Db.Variants
* <summary>
* Include Combos
* </summary>
*
* <remarks>
* @author Aloento
* @since 0.5.0
Expand Down Expand Up @@ -185,24 +183,28 @@ public async Task<bool> ProductDeleteProduct(uint prodId) {
* <remarks>
* @author Aloento
* @since 1.2.0
* @version 0.1.0
* @version 0.1.1
* </remarks>
*/
public async Task<bool> ProductDetachCategory(uint prodId) {
var prod = await this.Db.Products
.SingleAsync(x => x.ProductId == prodId);

if (prod.CategoryId is null)
var cate = prod.CategoryId;

if (cate is null)
return false;

prod.CategoryId = null;

var res = await this.Db.SaveChangesAsync();

await this.Db.Categories
.Where(x =>
x.CategoryId == prod.CategoryId &&
x.CategoryId == cate &&
x.Products.Count == 0)
.ExecuteDeleteAsync();

prod.CategoryId = null;

return await this.Db.SaveChangesAsync() > 0;
return res > 0;
}
}
3 changes: 2 additions & 1 deletion SoarCraft.AwaiShop/AdminHub/Product/Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ public async Task<bool> ProductPatchCaption(uint photoId, string caption) {

var row = await this.Db.Photos
.Where(x => x.PhotoId == photoId)
.ExecuteUpdateAsync(x => x.SetProperty(p => p.Caption, caption));
.ExecuteUpdateAsync(x =>
x.SetProperty(p => p.Caption, caption));

return row > 0;
}
Expand Down
8 changes: 4 additions & 4 deletions SoarCraft.AwaiShop/AdminHub/Product/Post.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ public async Task<bool> ProductPostMovePhoto(uint photoId, bool up) {
* <remarks>
* @author Aloento
* @since 0.5.0
* @version 0.1.0
* @version 0.1.1
* </remarks>
*/
public async Task<bool> ProductPostPhoto(uint prodId, IAsyncEnumerable<byte[]> input) {
public async Task<uint> ProductPostPhoto(uint prodId, IAsyncEnumerable<byte[]> input) {
var exist = await this.Db.Products.AnyAsync(x => x.ProductId == prodId);
if (!exist)
throw new HubException($"Product {prodId} not found");
Expand All @@ -95,14 +95,14 @@ public async Task<bool> ProductPostPhoto(uint prodId, IAsyncEnumerable<byte[]> i

var next = (byte)(await this.Db.Photos.CountAsync(x => x.ProductId == prodId) + 1);

await this.Db.Photos.AddAsync(new() {
var photo = await this.Db.Photos.AddAsync(new() {
ProductId = prodId,
Object = obj.Entity,
Order = next
});

await this.Db.SaveChangesAsync();
return true;
return photo.Entity.PhotoId;
}

/**
Expand Down
9 changes: 1 addition & 8 deletions SoarCraft.AwaiShop/Hub/Product/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ internal partial class ShopHub {
* <remarks>
* @author Aloento
* @since 0.5.0
* @version 0.1.0
* @version 0.1.1
* </remarks>
*/
public async Task<dynamic?> PhotoEntity(uint key, uint? version) {
Expand All @@ -69,13 +69,6 @@ internal partial class ShopHub {

return await this.Db.Photos
.Where(x => x.PhotoId == key)
.Select(x => new {
x.Cover,
x.Caption,
x.Order,
x.ObjectId,
x.Version
})
.SingleOrDefaultAsync();
}

Expand Down
30 changes: 11 additions & 19 deletions src/Pages/Admin/Product/Photo/Edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,14 @@ const useStyles = makeStyles({
}
});

/**
* @author Aloento
* @since 0.5.0
* @version 0.1.0
*/
interface IAdminProductPhotoEdit {
Photo: IPhotoItem;
Refresh: () => void;
}

const log = new Logger("Admin", "Product", "Detail", "Photo", "Edit");

/**
* @author Aloento
* @since 0.5.0
* @version 0.3.3
* @version 0.3.5
*/
export function AdminProductPhotoEdit({ Photo: { Id, Cover, Caption }, Refresh }: IAdminProductPhotoEdit) {
export function AdminProductPhotoEdit({ Id, Cover, Caption, ProductId }: IPhotoItem) {
const style = useStyles();
const [cap, setCap] = useState(Caption || "");

Expand All @@ -69,13 +59,19 @@ export function AdminProductPhotoEdit({ Photo: { Id, Cover, Caption }, Refresh }
</Toast>,
{ intent: "success" }
);

Refresh();
}
});

const { run: updateFile } = AdminHub.Product.Patch.usePhoto(log, {
manual: true,
onBefore([prodId, file]) {
dispatchToast(
<Toast>
<ToastTitle>Uploading Photo {file.name} for Product {prodId} to replace {Id}</ToastTitle>
</Toast>,
{ intent: "info" }
);
},
onError(e, req) {
dispatch({
Message: "Failed Update Photo",
Expand All @@ -90,8 +86,6 @@ export function AdminProductPhotoEdit({ Photo: { Id, Cover, Caption }, Refresh }
</Toast>,
{ intent: "success" }
);

Refresh();
}
});

Expand All @@ -111,8 +105,6 @@ export function AdminProductPhotoEdit({ Photo: { Id, Cover, Caption }, Refresh }
</Toast>,
{ intent: "success" }
);

Refresh();
}
});

Expand Down Expand Up @@ -166,7 +158,7 @@ export function AdminProductPhotoEdit({ Photo: { Id, Cover, Caption }, Refresh }
Replace
</Button>

<Button appearance="primary" onClick={() => deletePhoto(Id)}>
<Button appearance="primary" onClick={() => deletePhoto(ProductId, Id)}>
Delete
</Button>
</div>
Expand Down
54 changes: 28 additions & 26 deletions src/Pages/Admin/Product/Photo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Button, DataGridCell, DataGridHeaderCell, Subtitle1, TableColumnDefinition, Toast, ToastTitle, createTableColumn, makeStyles } from "@fluentui/react-components";
import { AddRegular, ArrowDownRegular, ArrowUpRegular } from "@fluentui/react-icons";
import { useRequest } from "ahooks";
import { useState } from "react";
import { useLiveQuery } from "dexie-react-hooks";
import { DelegateDataGrid } from "~/Components/DataGrid";
import { MakeCoverCol } from "~/Helpers/CoverCol";
import { Logger } from "~/Helpers/Logger";
Expand Down Expand Up @@ -32,19 +31,21 @@ const log = new Logger("Admin", "Product", "Detail", "Photo");
/**
* @author Aloento
* @since 0.5.0
* @version 0.1.0
* @version 0.2.0
*/
export interface IPhotoItem {
/** PhotoId */
Id: number;
/** ObjectId */
Cover: string;
Caption?: string;
ProductId: number;
}

/**
* @author Aloento
* @since 0.5.0
* @version 0.1.2
* @version 0.1.3
*/
const columns: TableColumnDefinition<IPhotoItem>[] = [
MakeCoverCol(70, log),
Expand Down Expand Up @@ -95,46 +96,49 @@ const columns: TableColumnDefinition<IPhotoItem>[] = [
onClick={() => run(item.Id, false)}
/>

<AdminProductPhotoEdit Photo={item} Refresh={refreshCarousel} />
<AdminProductPhotoEdit {...item} />
</DataGridCell>
)
},
})
]

/**
* @author Aloento
* @since 0.5.0
* @version 0.1.0
* @deprecated
*/
let refreshCarousel: () => void;
let refreshCarousel: () => void = () => { };

/**
* @author Aloento
* @since 0.5.0
* @version 0.4.0
* @version 0.5.0
*/
export function AdminProductPhoto({ ProdId }: { ProdId: number }) {
const [list, setList] = useState<IPhotoItem[]>([]);

const { run } = useRequest(() => Hub.Product.Get.PhotoList(ProdId, log), {
onError: log.error,
onSuccess([raw]) {
const map = raw.map(x => ({
Id: x.Order,
Cover: x.ObjectId,
Caption: x.Caption || "No Caption"
}));

setList(map);
}
const list = useLiveQuery<IPhotoItem[]>(async () => {
const [raw] = await Hub.Product.Get.PhotoList(ProdId, log);

const map = raw.map(x => ({
Id: x.PhotoId,
Cover: x.ObjectId,
Caption: x.Caption || "No Caption",
ProductId: x.ProductId
}));

return map;
});
refreshCarousel = run;

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

const { run: newPhoto } = AdminHub.Product.Post.usePhoto(log, {
manual: true,
onBefore([prodId, file]) {
dispatchToast(
<Toast>
<ToastTitle>Uploading Photo {file.name} for Product {prodId}</ToastTitle>
</Toast>,
{ intent: "info" }
);
},
onError(e, params) {
dispatch({
Message: "Failed Upload Photo",
Expand All @@ -149,8 +153,6 @@ export function AdminProductPhoto({ ProdId }: { ProdId: number }) {
</Toast>,
{ intent: "success" }
);

run();
}
});

Expand Down
9 changes: 6 additions & 3 deletions src/ShopNet/Admin/Product/Delete.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useRequest } from "ahooks";
import { Options } from "ahooks/lib/useRequest/src/types";
import { ProductData } from "~/ShopNet/Product/Data";
import { ProductGet } from "~/ShopNet/Product/Get";
import { AdminNet } from "../AdminNet";
import { AdminProductGet } from "./Get";

Expand All @@ -13,12 +14,14 @@ export abstract class AdminProductDelete extends AdminNet {
/**
* @author Aloento
* @since 0.5.0
* @version 0.2.0
* @version 0.3.0
*/
public static usePhoto(options: Options<true, [number]>) {
return useRequest(async photoId => {
public static usePhoto(options: Options<true, [number, number]>) {
return useRequest(async (prodId, photoId) => {
const res = await this.Invoke<boolean>("ProductDeletePhoto", photoId);
this.EnsureTrue(res);

ProductGet.PhotoListUpdate(prodId, x => x!.filter(x => x !== photoId));
return res;
}, options);
}
Expand Down
13 changes: 8 additions & 5 deletions src/ShopNet/Admin/Product/Post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Options } from "ahooks/lib/useRequest/src/types";
import { Subject } from "rxjs";
import { Logger } from "~/Helpers/Logger";
import { CurrentEditor } from "~/Lexical/Utils";
import { ProductGet } from "~/ShopNet/Product/Get";
import { AdminNet } from "../AdminNet";
import { AdminProductGet } from "./Get";

Expand Down Expand Up @@ -45,9 +46,9 @@ export abstract class AdminProductPost extends AdminNet {
/**
* @author Aloento
* @since 0.5.0
* @version 1.0.3
* @version 1.0.5
*/
public static usePhoto(pLog: Logger, options: Options<true, [number, File]>) {
public static usePhoto(pLog: Logger, options: Options<number, [number, File]>) {
const log = useConst(() => pLog.With(...this.Log, "Photo"));

return useRequest(async (prodId, file) => {
Expand All @@ -58,11 +59,13 @@ export abstract class AdminProductPost extends AdminNet {
throw new RangeError("File is too large, max 10MB");

const subject = new Subject<Uint8Array>();
const res = this.Invoke<boolean>("ProductPostPhoto", prodId, subject);
const res = this.Invoke<number>("ProductPostPhoto", prodId, subject);
await this.HandleFileStream(file, subject, log);

this.EnsureTrue(await res);
return true as const;
const id = await res;
ProductGet.PhotoListUpdate(prodId, x => [...x, id]);

return id;
}, options);
}

Expand Down
7 changes: 2 additions & 5 deletions src/ShopNet/Product/Data.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { IConcurrency } from "../Database";
import { ShopNet } from "../ShopNet";

/**
* @author Aloento
* @since 1.3.0
* @version 0.1.0
*/
export namespace ProductData {
export type Product = {
Name: string;
Expand All @@ -17,10 +12,12 @@ export namespace ProductData {
} & IConcurrency;

export type Photo = {
PhotoId: number;
Cover?: boolean;
Caption?: string;
Order: number;
ObjectId: string;
ProductId: number;
} & IConcurrency;

export type Type = {
Expand Down
Loading

0 comments on commit 1a5fa23

Please sign in to comment.