1import { beyond, by, from, into, type SchemaOf } from "@akanjs/document";
2
3import * as cnst from "../cnst";
4import { Revert } from "../dict";
5
6// ...other code
7
8export class IcecreamOrder extends by(cnst.IcecreamOrder) {
9 process() {
10 if (this.status !== "active") throw new Revert("icecreamOrder.error.onlyActiveCanBeProcessed");
11 this.status = "processing";
12 return this;
13 }
14 serve() {
15 if (this.status !== "processing") throw new Revert("icecreamOrder.error.onlyProcessingCanBeServed");
16 this.status = "served";
17 return this;
18 }
19 finish() {
20 if (this.status !== "served") throw new Revert("icecreamOrder.error.onlyServedCanBeFinished");
21 this.status = "finished";
22 return this;
23 }
24 cancel() {
25 if (this.status !== "active") throw new Revert("icecreamOrder.error.onlyActiveCanBeCanceled");
26 this.status = "canceled";
27 return this;
28 }
29}
30// ...other code1// ...other code
2export const dictionary = modelDictionary(["en", "ko"])
3 // ...other code
4
5 .error({
6 onlyActiveCanBeProcessed: ["Only active orders can be processed", "활성 상태의 주문만 처리할 수 있습니다"],
7 onlyProcessingCanBeServed: ["Only processing orders can be served", "처리중인 주문만 서빙할 수 있습니다"],
8 onlyServedCanBeFinished: ["Only served orders can be finished", "서빙완료된 주문만 완료할 수 있습니다"],
9 onlyActiveCanBeCanceled: ["Only active orders can be canceled", "활성 상태의 주문만 취소할 수 있습니다"],
10 })
11 .translate({});1import { serve } from "@akanjs/service";
2
3import * as cnst from "../cnst";
4import * as db from "../db";
5
6export class IcecreamOrderService extends serve(db.icecreamOrder, () => ({})) {
7 async processIcecreamOrder(icecreamOrderId: string) {
8 const icecreamOrder = await this.getIcecreamOrder(icecreamOrderId);
9 return await icecreamOrder.process().save();
10 }
11 async serveIcecreamOrder(icecreamOrderId: string) {
12 const icecreamOrder = await this.getIcecreamOrder(icecreamOrderId);
13 return await icecreamOrder.serve().save();
14 }
15 async finishIcecreamOrder(icecreamOrderId: string) {
16 const icecreamOrder = await this.getIcecreamOrder(icecreamOrderId);
17 return await icecreamOrder.finish().save();
18 }
19 async cancelIcecreamOrder(icecreamOrderId: string) {
20 const icecreamOrder = await this.getIcecreamOrder(icecreamOrderId);
21 return await icecreamOrder.cancel().save();
22 }
23}1import { ID } from "@akanjs/base";
2
3// ...existing code
4
5export class IcecreamOrderEndpoint extends endpoint(srv.icecreamOrder, ({ mutation }) => ({
6 processIcecreamOrder: mutation(cnst.IcecreamOrder)
7 .param("icecreamOrderId", ID)
8 .exec(function (icecreamOrderId) {
9 return this.icecreamOrderService.processIcecreamOrder(icecreamOrderId);
10 }),
11 serveIcecreamOrder: mutation(cnst.IcecreamOrder)
12 .param("icecreamOrderId", ID)
13 .exec(function (icecreamOrderId) {
14 return this.icecreamOrderService.serveIcecreamOrder(icecreamOrderId);
15 }),
16 finishIcecreamOrder: mutation(cnst.IcecreamOrder)
17 .param("icecreamOrderId", ID)
18 .exec(function (icecreamOrderId) {
19 return this.icecreamOrderService.finishIcecreamOrder(icecreamOrderId);
20 }),
21 cancelIcecreamOrder: mutation(cnst.IcecreamOrder)
22 .param("icecreamOrderId", ID)
23 .exec(function (icecreamOrderId) {
24 return this.icecreamOrderService.cancelIcecreamOrder(icecreamOrderId);
25 }),
26})) {}1// ...other code
2export const dictionary = modelDictionary(["en", "ko"])
3 // ...other code
4
5 .endpoint<IcecreamOrderEndpoint>((fn) => ({
6 processIcecreamOrder: fn(["Process", "작업시작"])
7 .desc(["Start processing an ice cream order", "아이스크림 주문 처리를 시작합니다"])
8 .arg((t) => ({
9 icecreamOrderId: t(["Order ID", "주문 ID"]).desc(["ID of the order to process", "처리할 주문의 ID"]),
10 })),
11 serveIcecreamOrder: fn(["Serve", "서빙완료"])
12 .desc(["Mark an ice cream order as served", "아이스크림 주문을 서빙완료로 표시합니다"])
13 .arg((t) => ({
14 icecreamOrderId: t(["Order ID", "주문 ID"]).desc(["ID of the order to serve", "서빙할 주문의 ID"]),
15 })),
16 finishIcecreamOrder: fn(["Finish", "완료"])
17 .desc(["Mark an ice cream order as finished", "아이스크림 주문을 완료로 표시합니다"])
18 .arg((t) => ({
19 icecreamOrderId: t(["Order ID", "주문 ID"]).desc(["ID of the order to finish", "완료할 주문의 ID"]),
20 })),
21 cancelIcecreamOrder: fn(["Cancel", "주문취소"])
22 .desc(["Cancel an ice cream order", "아이스크림 주문을 취소합니다"])
23 .arg((t) => ({
24 icecreamOrderId: t(["Order ID", "주문 ID"]).desc(["ID of the order to cancel", "취소할 주문의 ID"]),
25 })),
26 }))
27 .error({
28 // ...other code
29 1import { stateOf, Store } from "@akanjs/store";
2
3import * as cnst from "../cnst";
4import { fetch, sig } from "../sig";
5
6export class IcecreamOrderStore extends stateOf(fetch.icecreamOrderGql, {
7 // state
8}) {
9 async processIcecreamOrder(icecreamOrderId: string) {
10 const icecreamOrder = await fetch.processIcecreamOrder(icecreamOrderId);
11 this.setIcecreamOrder(icecreamOrder);
12 }
13 async serveIcecreamOrder(icecreamOrderId: string) {
14 const icecreamOrder = await fetch.serveIcecreamOrder(icecreamOrderId);
15 this.setIcecreamOrder(icecreamOrder);
16 }
17 async finishIcecreamOrder(icecreamOrderId: string) {
18 const icecreamOrder = await fetch.finishIcecreamOrder(icecreamOrderId);
19 this.setIcecreamOrder(icecreamOrder);
20 }
21 async cancelIcecreamOrder(icecreamOrderId: string) {
22 const icecreamOrder = await fetch.cancelIcecreamOrder(icecreamOrderId);
23 this.setIcecreamOrder(icecreamOrder);
24 }
25}1"use client";
2import { clsx } from "@akanjs/client";
3import { st, usePage } from "@koyo/client";
4
5interface ProcessProps {
6 className?: string;
7 icecreamOrderId: string;
8 disabled?: boolean;
9}
10export const Process = ({ className, icecreamOrderId, disabled }: ProcessProps) => {
11 const { l } = usePage();
12 return (
13 <button
14 className={clsx("btn btn-secondary", className)}
15 disabled={disabled}
16 onClick={() => {
17 void st.do.processIcecreamOrder(icecreamOrderId);
18 }}
19 >
20 {l("icecreamOrder.signal.processIcecreamOrder")}
21 </button>
22 );
23};
24
25interface ServeProps {
26 className?: string;
27 icecreamOrderId: string;
28 disabled?: boolean;
29}
30export const Serve = ({ className, icecreamOrderId, disabled }: ServeProps) => {
31 const { l } = usePage();
32 return (
33 <button
34 className={clsx("btn btn-accent", className)}
35 disabled={disabled}
36 onClick={() => {
37 void st.do.serveIcecreamOrder(icecreamOrderId);
38 }}
39 >
40 {l("icecreamOrder.signal.serveIcecreamOrder")}
41 </button>
42 );
43};
44
45interface FinishProps {
46 className?: string;
47 icecreamOrderId: string;
48 disabled?: boolean;
49}
50export const Finish = ({ className, icecreamOrderId, disabled }: FinishProps) => {
51 const { l } = usePage();
52 return (
53 <button
54 className={clsx("btn btn-success", className)}
55 disabled={disabled}
56 onClick={() => {
57 void st.do.finishIcecreamOrder(icecreamOrderId);
58 }}
59 >
60 {l("icecreamOrder.signal.finishIcecreamOrder")}
61 </button>
62 );
63};
64
65interface CancelProps {
66 className?: string;
67 icecreamOrderId: string;
68 disabled?: boolean;
69}
70export const Cancel = ({ className, icecreamOrderId, disabled }: CancelProps) => {
71 const { l } = usePage();
72 return (
73 <button
74 className={clsx("btn btn-warning", className)}
75 disabled={disabled}
76 onClick={() => {
77 void st.do.cancelIcecreamOrder(icecreamOrderId);
78 }}
79 >
80 {l("icecreamOrder.signal.cancelIcecreamOrder")}
81 </button>
82 );
83};1import { clsx, ModelProps } from "@akanjs/client";
2import { Model } from "@akanjs/ui";
3import { cnst, IcecreamOrder, usePage } from "@koyo/client";
4
5export const Card = ({ icecreamOrder }: ModelProps<"icecreamOrder", cnst.LightIcecreamOrder>) => {
6 const { l } = usePage();
7 return (
8 <div className="group flex h-auto w-full flex-col overflow-hidden rounded-xl bg-linear-to-br from-pink-100 via-yellow-50 to-pink-200 p-6 shadow-md transition-all duration-300 hover:shadow-xl">
9 {/* Order information section */}
10 <div className="flex w-full flex-col justify-center space-y-4">
11 <div className="flex items-center gap-2 text-lg font-semibold text-pink-700">
12 <span className="inline-block rounded bg-pink-200 px-2 py-1 text-xs font-bold tracking-wider uppercase">
13 {l("icecreamOrder.id")}
14 </span>
15 <span className="ml-2 font-mono text-pink-900">#{icecreamOrder.id.slice(-4)}</span>
16 </div>
17 <div className="flex items-center gap-2">
18 <span className="inline-block rounded bg-yellow-200 px-2 py-1 text-xs font-bold tracking-wider text-yellow-800 uppercase">
19 {l("icecreamOrder.status")}
20 </span>
21 <span
22 className={clsx("ml-2 rounded-full px-3 py-1 text-sm font-semibold", {
23 "bg-green-100 text-green-700": icecreamOrder.status === "active",
24 "bg-blue-100 text-blue-700": icecreamOrder.status === "processing",
25 "bg-red-100 text-red-700": icecreamOrder.status === "served",
26 "bg-purple-100 text-purple-700": icecreamOrder.status === "finished",
27 "bg-gray-100 text-gray-700": icecreamOrder.status === "canceled",
28 })}
29 >
30 {l(`icecreamOrderStatus.${icecreamOrder.status}`)}
31 </span>
32 </div>
33 </div>
34
35 {/* Action buttons section */}
36 <div className="bg-base-100/50 flex items-center justify-center gap-2 rounded-xl p-4">
37 <Model.ViewWrapper sliceName="icecreamOrder" modelId={icecreamOrder.id}>
38 <button className="btn btn-primary btn-xl">
39 <span>{l.trans({ en: "View", ko: "보기" })}</span>
40 </button>
41 </Model.ViewWrapper>42 <IcecreamOrder.Util.Process icecreamOrderId={icecreamOrder.id} disabled={icecreamOrder.status !== "active"} />
43 <IcecreamOrder.Util.Serve icecreamOrderId={icecreamOrder.id} disabled={icecreamOrder.status !== "processing"} />
44 <IcecreamOrder.Util.Finish icecreamOrderId={icecreamOrder.id} disabled={icecreamOrder.status !== "served"} />
45 <IcecreamOrder.Util.Cancel icecreamOrderId={icecreamOrder.id} disabled={icecreamOrder.status !== "active"} />46 </div>
47 </div>
48 );
49};1import { clsx } from "@akanjs/client";
2import { cnst, IcecreamOrder, usePage } from "@koyo/client";
3
4interface IcecreamOrderViewProps {
5 className?: string;
6 icecreamOrder: cnst.IcecreamOrder;
7}
8
9export const General = ({ className, icecreamOrder }: IcecreamOrderViewProps) => {
10 const { l } = usePage();
11 return (
12 <div className={clsx(className, "mx-auto w-full space-y-6 rounded-xl p-8 shadow-lg")}>
13 {/* Header section */}
14 <div className="flex items-center gap-3 border-b pb-4">
15 <span className="text-3xl font-extrabold text-pink-600">🍦</span>
16 <span className="text-2xl font-bold">{l("icecreamOrder.modelName")}</span>
17 <span className="ml-auto text-xs text-base-content/50">#{icecreamOrder.id}</span>
18 </div>
19
20 {/* Order details grid - same as before */}
21 <div className="grid grid-cols-2 gap-x-6 gap-y-4">
22 {/* ... existing field displays ... */}
23 </div>
24
25 {/* Action buttons section */}
26 <div className="flex items-center justify-end gap-2">
27 <IcecreamOrder.Util.Process icecreamOrderId={icecreamOrder.id} disabled={icecreamOrder.status !== "active"} />
28 <IcecreamOrder.Util.Serve icecreamOrderId={icecreamOrder.id} disabled={icecreamOrder.status !== "processing"} />
29 <IcecreamOrder.Util.Finish icecreamOrderId={icecreamOrder.id} disabled={icecreamOrder.status !== "served"} />
30 <IcecreamOrder.Util.Cancel icecreamOrderId={icecreamOrder.id} disabled={icecreamOrder.status !== "active"} />
31 </div>
32 </div>
33 );
34};