create-cundi-app 1.0.18 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-cundi-app",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "description": "Create a new Cundi app with React + Refine + Ant Design",
5
5
  "type": "module",
6
6
  "bin": {
@@ -78,6 +78,7 @@ import { DrawioTestList } from "./pages/samples/drawio-test/list";
78
78
  import { DrawioTestCreate } from "./pages/samples/drawio-test/create";
79
79
  import { DrawioTestEdit } from "./pages/samples/drawio-test/edit";
80
80
  import { DrawioTestShow } from "./pages/samples/drawio-test/show";
81
+ import { OrderList, OrderCreate, OrderEdit, OrderShow } from "./pages/samples/order";
81
82
 
82
83
  // {CHAT_START}
83
84
  import { ChatProvider } from "./components/ChatPanel";
@@ -138,6 +139,17 @@ const InnerApp: React.FC = () => {
138
139
  parent: "Model",
139
140
  },
140
141
  },
142
+ {
143
+ name: "Order",
144
+ list: "/Orders",
145
+ create: "/Orders/create",
146
+ edit: "/Orders/edit/:id",
147
+ show: "/Orders/show/:id",
148
+ meta: {
149
+ label: t("sider.order"),
150
+ parent: "Model",
151
+ },
152
+ },
141
153
  {
142
154
  name: "TiptapTest",
143
155
  list: "/TiptapTests",
@@ -317,6 +329,13 @@ const InnerApp: React.FC = () => {
317
329
  <Route path="show/:id" element={<DrawioTestShow />} />
318
330
  </Route>
319
331
 
332
+ <Route path="/Orders">
333
+ <Route index element={<OrderList />} />
334
+ <Route path="create" element={<OrderCreate />} />
335
+ <Route path="edit/:id" element={<OrderEdit />} />
336
+ <Route path="show/:id" element={<OrderShow />} />
337
+ </Route>
338
+
320
339
  {/* Core routes */}
321
340
  <Route path="/ApplicationUsers">
322
341
  <Route index element={<ApplicationUserList />} />
@@ -17,6 +17,7 @@ const enExtended = {
17
17
  samples: "Samples",
18
18
  model: "Model",
19
19
  basicTypeTest: "Basic Type",
20
+ order: "Master-Details",
20
21
  tiptapTest: "Tiptap Editor",
21
22
  drawioTest: "Drawio Editor",
22
23
  fullTextSearch: "Full Text Search",
@@ -53,12 +54,39 @@ const enExtended = {
53
54
  doubleValue: "Double Value",
54
55
  dateTimeValue: "DateTime Value",
55
56
  boolValue: "Bool Value",
57
+ statusValue: "Status",
58
+ status: {
59
+ Draft: "Draft",
60
+ Active: "Active",
61
+ Completed: "Completed",
62
+ Cancelled: "Cancelled",
63
+ },
56
64
  imageValue: "Image Value",
57
65
  },
66
+ order: {
67
+ orderNumber: "Order Number",
68
+ orderDate: "Order Date",
69
+ customerName: "Customer Name",
70
+ notes: "Notes",
71
+ totalAmount: "Total Amount",
72
+ items: "Order Items",
73
+ },
74
+ orderItem: {
75
+ title: "Order Item",
76
+ productName: "Product Name",
77
+ quantity: "Quantity",
78
+ unitPrice: "Unit Price",
79
+ subtotal: "Subtotal",
80
+ },
81
+ validation: {
82
+ required: "This field is required",
83
+ },
58
84
  types: {
59
85
  Article: "Article",
60
86
  Product: "Product",
61
87
  BasicTypeTest: "Basic Type",
88
+ Order: "Order",
89
+ OrderItem: "Order Item",
62
90
  },
63
91
  };
64
92
 
@@ -73,6 +101,7 @@ const zhTWExtended = {
73
101
  samples: "範例",
74
102
  model: "資料模型",
75
103
  basicTypeTest: "基本型別",
104
+ order: "主從式資料",
76
105
  tiptapTest: "Tiptap 編輯器",
77
106
  drawioTest: "Drawio 編輯器",
78
107
  fullTextSearch: "全文檢索",
@@ -109,12 +138,39 @@ const zhTWExtended = {
109
138
  doubleValue: "浮點數",
110
139
  dateTimeValue: "日期時間",
111
140
  boolValue: "布林值",
141
+ statusValue: "狀態",
142
+ status: {
143
+ Draft: "草稿",
144
+ Active: "啟用",
145
+ Completed: "完成",
146
+ Cancelled: "取消",
147
+ },
112
148
  imageValue: "圖片",
113
149
  },
150
+ order: {
151
+ orderNumber: "訂單編號",
152
+ orderDate: "訂單日期",
153
+ customerName: "客戶名稱",
154
+ notes: "備註",
155
+ totalAmount: "總金額",
156
+ items: "訂單明細",
157
+ },
158
+ orderItem: {
159
+ title: "訂單明細",
160
+ productName: "產品名稱",
161
+ quantity: "數量",
162
+ unitPrice: "單價",
163
+ subtotal: "小計",
164
+ },
165
+ validation: {
166
+ required: "此欄位為必填",
167
+ },
114
168
  types: {
115
169
  Article: "文章",
116
170
  Product: "產品",
117
171
  BasicTypeTest: "基本型別",
172
+ Order: "訂單",
173
+ OrderItem: "訂單明細",
118
174
  },
119
175
  };
120
176
 
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { Create, useForm } from "@refinedev/antd";
3
- import { Form, Input, InputNumber, DatePicker, Switch } from "antd";
3
+ import { Form, Input, InputNumber, DatePicker, Switch, Select } from "antd";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { Base64Upload } from "@cundi/refine-xaf";
6
6
  import dayjs from "dayjs";
@@ -56,6 +56,19 @@ export const BasicTypeTestCreate: React.FC = () => {
56
56
  >
57
57
  <Switch />
58
58
  </Form.Item>
59
+ <Form.Item
60
+ label={t("basicTypeTest.statusValue")}
61
+ name="StatusValue"
62
+ >
63
+ <Select
64
+ options={[
65
+ { value: "Draft", label: t("basicTypeTest.status.Draft") },
66
+ { value: "Active", label: t("basicTypeTest.status.Active") },
67
+ { value: "Completed", label: t("basicTypeTest.status.Completed") },
68
+ { value: "Cancelled", label: t("basicTypeTest.status.Cancelled") },
69
+ ]}
70
+ />
71
+ </Form.Item>
59
72
  <Form.Item
60
73
  label={t("basicTypeTest.imageValue")}
61
74
  name="ImageValue"
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { Edit, useForm } from "@refinedev/antd";
3
- import { Form, Input, InputNumber, DatePicker, Switch } from "antd";
3
+ import { Form, Input, InputNumber, DatePicker, Switch, Select } from "antd";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { Base64Upload } from "@cundi/refine-xaf";
6
6
  import dayjs from "dayjs";
@@ -56,6 +56,19 @@ export const BasicTypeTestEdit: React.FC = () => {
56
56
  >
57
57
  <Switch />
58
58
  </Form.Item>
59
+ <Form.Item
60
+ label={t("basicTypeTest.statusValue")}
61
+ name="StatusValue"
62
+ >
63
+ <Select
64
+ options={[
65
+ { value: "Draft", label: t("basicTypeTest.status.Draft") },
66
+ { value: "Active", label: t("basicTypeTest.status.Active") },
67
+ { value: "Completed", label: t("basicTypeTest.status.Completed") },
68
+ { value: "Cancelled", label: t("basicTypeTest.status.Cancelled") },
69
+ ]}
70
+ />
71
+ </Form.Item>
59
72
  <Form.Item
60
73
  label={t("basicTypeTest.imageValue")}
61
74
  name="ImageValue"
@@ -46,6 +46,22 @@ export const BasicTypeTestList: React.FC = () => {
46
46
  // @ts-ignore
47
47
  defaultVisible
48
48
  />
49
+ <Table.Column
50
+ dataIndex="StatusValue"
51
+ title={t("basicTypeTest.statusValue")}
52
+ sorter
53
+ render={(value: string) => (
54
+ <Tag color={
55
+ value === "Active" ? "green" :
56
+ value === "Completed" ? "blue" :
57
+ value === "Cancelled" ? "red" : "default"
58
+ }>
59
+ {t(`basicTypeTest.status.${value}`, value)}
60
+ </Tag>
61
+ )}
62
+ // @ts-ignore
63
+ defaultVisible
64
+ />
49
65
  <Table.Column
50
66
  dataIndex="ImageValue"
51
67
  title={t("basicTypeTest.imageValue")}
@@ -0,0 +1,50 @@
1
+ import React from "react";
2
+ import { Create, useForm } from "@refinedev/antd";
3
+ import { Form, Input, DatePicker } from "antd";
4
+ import { useTranslation } from "react-i18next";
5
+ import dayjs from "dayjs";
6
+
7
+ export const OrderCreate: React.FC = () => {
8
+ const { t } = useTranslation();
9
+ const { formProps, saveButtonProps } = useForm({
10
+ redirect: "edit",
11
+ });
12
+
13
+ return (
14
+ <Create saveButtonProps={saveButtonProps}>
15
+ <Form {...formProps} layout="vertical">
16
+ <Form.Item
17
+ label={t("order.orderNumber")}
18
+ name="OrderNumber"
19
+ rules={[{ required: true, message: t("validation.required") }]}
20
+ >
21
+ <Input />
22
+ </Form.Item>
23
+ <Form.Item
24
+ label={t("order.orderDate")}
25
+ name="OrderDate"
26
+ getValueProps={(value) => ({
27
+ value: value ? dayjs(value) : dayjs(),
28
+ })}
29
+ getValueFromEvent={(date) => date?.toISOString()}
30
+ rules={[{ required: true, message: t("validation.required") }]}
31
+ >
32
+ <DatePicker style={{ width: "100%" }} />
33
+ </Form.Item>
34
+ <Form.Item
35
+ label={t("order.customerName")}
36
+ name="CustomerName"
37
+ rules={[{ required: true, message: t("validation.required") }]}
38
+ >
39
+ <Input />
40
+ </Form.Item>
41
+ <Form.Item
42
+ label={t("order.notes")}
43
+ name="Notes"
44
+ >
45
+ <Input.TextArea rows={3} />
46
+ </Form.Item>
47
+ </Form>
48
+ </Create>
49
+ );
50
+ };
@@ -0,0 +1,139 @@
1
+ import React from "react";
2
+ import { Edit, useForm } from "@refinedev/antd";
3
+ import { Form, Input, DatePicker, InputNumber, Card } from "antd";
4
+ import { useTranslation } from "react-i18next";
5
+ import { RelatedList } from "@cundi/refine-xaf";
6
+ import { useTable } from "@refinedev/antd";
7
+ import { Table } from "antd";
8
+ import dayjs from "dayjs";
9
+
10
+ // OrderItem Form Fields Component
11
+ const OrderItemFormFields: React.FC<{ mode: "create" | "edit" }> = () => {
12
+ const { t } = useTranslation();
13
+
14
+ return (
15
+ <>
16
+ <Form.Item
17
+ label={t("orderItem.productName")}
18
+ name="ProductName"
19
+ rules={[{ required: true, message: t("validation.required") }]}
20
+ >
21
+ <Input />
22
+ </Form.Item>
23
+ <Form.Item
24
+ label={t("orderItem.quantity")}
25
+ name="Quantity"
26
+ rules={[{ required: true, message: t("validation.required") }]}
27
+ >
28
+ <InputNumber min={1} style={{ width: "100%" }} />
29
+ </Form.Item>
30
+ <Form.Item
31
+ label={t("orderItem.unitPrice")}
32
+ name="UnitPrice"
33
+ rules={[{ required: true, message: t("validation.required") }]}
34
+ >
35
+ <InputNumber min={0} precision={2} style={{ width: "100%" }} prefix="$" />
36
+ </Form.Item>
37
+ </>
38
+ );
39
+ };
40
+
41
+ export const OrderEdit: React.FC = () => {
42
+ const { t } = useTranslation();
43
+ const { formProps, saveButtonProps, query } = useForm({
44
+ meta: {
45
+ expand: ["Items"],
46
+ },
47
+ });
48
+
49
+ const orderId = query?.data?.data?.Oid as string | undefined;
50
+
51
+ // Fetch order items for the RelatedList
52
+ const { tableProps } = useTable({
53
+ resource: "OrderItem",
54
+ filters: {
55
+ permanent: [
56
+ { field: "Order/Oid", operator: "eq", value: orderId || "" }
57
+ ]
58
+ },
59
+ syncWithLocation: false,
60
+ queryOptions: {
61
+ enabled: !!orderId,
62
+ },
63
+ pagination: {
64
+ mode: "off"
65
+ }
66
+ });
67
+
68
+ // Convert readonly array to mutable array for RelatedList
69
+ const dataSource = tableProps.dataSource ? [...tableProps.dataSource] : [];
70
+
71
+ return (
72
+ <Edit saveButtonProps={saveButtonProps}>
73
+ <Form {...formProps} layout="vertical">
74
+ <Form.Item
75
+ label={t("order.orderNumber")}
76
+ name="OrderNumber"
77
+ rules={[{ required: true, message: t("validation.required") }]}
78
+ >
79
+ <Input />
80
+ </Form.Item>
81
+ <Form.Item
82
+ label={t("order.orderDate")}
83
+ name="OrderDate"
84
+ getValueProps={(value) => ({
85
+ value: value ? dayjs(value) : null,
86
+ })}
87
+ getValueFromEvent={(date) => date?.toISOString()}
88
+ rules={[{ required: true, message: t("validation.required") }]}
89
+ >
90
+ <DatePicker style={{ width: "100%" }} />
91
+ </Form.Item>
92
+ <Form.Item
93
+ label={t("order.customerName")}
94
+ name="CustomerName"
95
+ rules={[{ required: true, message: t("validation.required") }]}
96
+ >
97
+ <Input />
98
+ </Form.Item>
99
+ <Form.Item
100
+ label={t("order.notes")}
101
+ name="Notes"
102
+ >
103
+ <Input.TextArea rows={3} />
104
+ </Form.Item>
105
+ </Form>
106
+
107
+ {/* Order Items (Details) */}
108
+ <Card title={t("order.items")} style={{ marginTop: 16 }}>
109
+ <RelatedList
110
+ resource="OrderItem"
111
+ masterField="Order"
112
+ masterId={orderId}
113
+ dataSource={dataSource}
114
+ FormFields={OrderItemFormFields}
115
+ modalTitle={t("orderItem.title")}
116
+ >
117
+ <Table.Column
118
+ dataIndex="ProductName"
119
+ title={t("orderItem.productName")}
120
+ />
121
+ <Table.Column
122
+ dataIndex="Quantity"
123
+ title={t("orderItem.quantity")}
124
+ />
125
+ <Table.Column
126
+ dataIndex="UnitPrice"
127
+ title={t("orderItem.unitPrice")}
128
+ render={(value: number) => value ? `$${value.toFixed(2)}` : "-"}
129
+ />
130
+ <Table.Column
131
+ dataIndex="Subtotal"
132
+ title={t("orderItem.subtotal")}
133
+ render={(value: number) => value ? `$${value.toFixed(2)}` : "-"}
134
+ />
135
+ </RelatedList>
136
+ </Card>
137
+ </Edit>
138
+ );
139
+ };
@@ -0,0 +1,4 @@
1
+ export { OrderList } from "./list";
2
+ export { OrderCreate } from "./create";
3
+ export { OrderEdit } from "./edit";
4
+ export { OrderShow } from "./show";
@@ -0,0 +1,59 @@
1
+ import React from "react";
2
+ import { BaseRecord } from "@refinedev/core";
3
+ import { EditButton, ShowButton, DeleteButton } from "@refinedev/antd";
4
+ import { Table, Space, Tag } from "antd";
5
+ import { SmartList } from "@cundi/refine-xaf";
6
+ import { useTranslation } from "react-i18next";
7
+
8
+ export const OrderList: React.FC = () => {
9
+ const { t } = useTranslation();
10
+
11
+ return (
12
+ <SmartList
13
+ resource="Order"
14
+ searchFields={["OrderNumber", "CustomerName"]}
15
+ >
16
+ <Table.Column
17
+ dataIndex="OrderNumber"
18
+ title={t("order.orderNumber")}
19
+ sorter
20
+ // @ts-ignore
21
+ defaultVisible
22
+ />
23
+ <Table.Column
24
+ dataIndex="OrderDate"
25
+ title={t("order.orderDate")}
26
+ sorter
27
+ render={(value: string) => value ? new Date(value).toLocaleDateString() : "-"}
28
+ // @ts-ignore
29
+ defaultVisible
30
+ />
31
+ <Table.Column
32
+ dataIndex="CustomerName"
33
+ title={t("order.customerName")}
34
+ sorter
35
+ // @ts-ignore
36
+ defaultVisible
37
+ />
38
+ <Table.Column
39
+ dataIndex="TotalAmount"
40
+ title={t("order.totalAmount")}
41
+ sorter
42
+ render={(value: number) => value ? `$${value.toFixed(2)}` : "$0.00"}
43
+ // @ts-ignore
44
+ defaultVisible
45
+ />
46
+ <Table.Column
47
+ title={t("buttons.list")}
48
+ dataIndex="actions"
49
+ render={(_, record: BaseRecord) => (
50
+ <Space>
51
+ <EditButton hideText size="small" recordItemId={record.Oid} />
52
+ <ShowButton hideText size="small" recordItemId={record.Oid} />
53
+ <DeleteButton hideText size="small" recordItemId={record.Oid} />
54
+ </Space>
55
+ )}
56
+ />
57
+ </SmartList>
58
+ );
59
+ };
@@ -0,0 +1,69 @@
1
+ import React from "react";
2
+ import { Show } from "@refinedev/antd";
3
+ import { useShow } from "@refinedev/core";
4
+ import { Typography, Table, Card, Descriptions } from "antd";
5
+ import { useTranslation } from "react-i18next";
6
+
7
+ const { Title } = Typography;
8
+
9
+ export const OrderShow: React.FC = () => {
10
+ const { t } = useTranslation();
11
+ const { query } = useShow({
12
+ meta: {
13
+ expand: ["Items"],
14
+ },
15
+ });
16
+ const { data, isLoading } = query;
17
+ const record = data?.data;
18
+
19
+ return (
20
+ <Show isLoading={isLoading}>
21
+ <Descriptions bordered column={1}>
22
+ <Descriptions.Item label={t("order.orderNumber")}>
23
+ {record?.OrderNumber}
24
+ </Descriptions.Item>
25
+ <Descriptions.Item label={t("order.orderDate")}>
26
+ {record?.OrderDate ? new Date(record.OrderDate).toLocaleDateString() : "-"}
27
+ </Descriptions.Item>
28
+ <Descriptions.Item label={t("order.customerName")}>
29
+ {record?.CustomerName}
30
+ </Descriptions.Item>
31
+ <Descriptions.Item label={t("order.totalAmount")}>
32
+ ${record?.TotalAmount?.toFixed(2) || "0.00"}
33
+ </Descriptions.Item>
34
+ <Descriptions.Item label={t("order.notes")}>
35
+ {record?.Notes || "-"}
36
+ </Descriptions.Item>
37
+ </Descriptions>
38
+
39
+ <Card title={t("order.items")} style={{ marginTop: 16 }}>
40
+ <Table
41
+ dataSource={record?.Items || []}
42
+ rowKey="Oid"
43
+ pagination={false}
44
+ bordered
45
+ size="small"
46
+ >
47
+ <Table.Column
48
+ dataIndex="ProductName"
49
+ title={t("orderItem.productName")}
50
+ />
51
+ <Table.Column
52
+ dataIndex="Quantity"
53
+ title={t("orderItem.quantity")}
54
+ />
55
+ <Table.Column
56
+ dataIndex="UnitPrice"
57
+ title={t("orderItem.unitPrice")}
58
+ render={(value: number) => value ? `$${value.toFixed(2)}` : "-"}
59
+ />
60
+ <Table.Column
61
+ dataIndex="Subtotal"
62
+ title={t("orderItem.subtotal")}
63
+ render={(value: number) => value ? `$${value.toFixed(2)}` : "-"}
64
+ />
65
+ </Table>
66
+ </Card>
67
+ </Show>
68
+ );
69
+ };