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