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

[Back] ProductDetachCategory | ProductPostPhoto | PhotoEntity - [Front] AdminProductPhotoEdit | AdminProductPhoto #96

Merged
merged 2 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading