umwd-components 0.1.710 → 0.1.712
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/dist/node_modules/base64-js/index.js +1 -1
- package/dist/node_modules/ieee754/index.js +1 -1
- package/dist/src/data/loaders/e-commerce/getAllCustomers.js +1 -1
- package/dist/src/data/loaders/e-commerce/getAllInvoices.js +1 -1
- package/dist/src/data/loaders/e-commerce/getTableProducts.js +1 -1
- package/dist/src/data/loaders/e-commerce/iros/getAllIros.js +1 -1
- package/dist/src/data/loaders/logistics/getTableIpos.js +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/data/loaders/e-commerce/getAllCustomers.d.ts +4 -1
- package/dist/types/data/loaders/e-commerce/getAllInvoices.d.ts +9 -1
- package/dist/types/data/loaders/e-commerce/getAllOpos.d.ts +5 -1
- package/dist/types/data/loaders/e-commerce/getTableProducts.d.ts +9 -1
- package/dist/types/data/loaders/e-commerce/iros/getAllIros.d.ts +8 -1
- package/dist/types/data/loaders/logistics/getTableIpos.d.ts +9 -1
- package/dist/types/lib/utils.d.ts +10 -0
- package/package.json +1 -1
- package/src/app/page.tsx +2 -0
- package/src/data/loaders/e-commerce/getAllCustomers.ts +16 -8
- package/src/data/loaders/e-commerce/getAllInvoices.ts +20 -3
- package/src/data/loaders/e-commerce/getAllOpos.ts +6 -1
- package/src/data/loaders/e-commerce/getTableProducts.ts +14 -7
- package/src/data/loaders/e-commerce/iros/getAllIros.ts +10 -1
- package/src/data/loaders/logistics/getTableIpos.ts +13 -6
- package/src/lib/utils.ts +10 -0
- package/.ai/action-patterns.md +0 -170
- package/.ai/form-patterns.instruction.md +0 -0
- package/.ai/form-patterns.md +0 -198
- package/.ai/form-patterns.prompt.md +0 -0
- package/.ai/instructions/form-patterns.instructions.md +0 -150
- package/.ai/prompts/form-patterns.prompt.md +0 -171
- package/.ai/prompts/update-form-and-actions.prompt.md +0 -20
- package/.vscode/settings.json +0 -7
|
@@ -1 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
declare function getAllCustomers(currentPage: number, rowsPerPage: number, order: "asc" | "desc", orderBy: string, filters?: {
|
|
2
|
+
[key: string]: string;
|
|
3
|
+
}): Promise<any>;
|
|
4
|
+
export { getAllCustomers };
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* INFO Fetch all Invoices
|
|
3
|
+
* used by the Invoices table in the admin panel
|
|
4
|
+
*/
|
|
5
|
+
declare function getAllInvoices(currentPage: number, rowsPerPage: number, order: "asc" | "desc", orderBy: string, is_archive?: boolean[], // default to only non-archived OPOs
|
|
6
|
+
filters?: {
|
|
7
|
+
[key: string]: string;
|
|
8
|
+
}): Promise<any>;
|
|
9
|
+
export { getAllInvoices };
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* INFO Fetch all OPOs
|
|
3
|
+
* used by the OPOs table in the admin panel
|
|
4
|
+
*/
|
|
5
|
+
declare function getAllOpos(currentPage: number, rowsPerPage: number, order: "asc" | "desc", orderBy: string, is_archive?: boolean[], // default to only non-archived OPOs
|
|
2
6
|
filters?: {
|
|
3
7
|
[key: string]: string;
|
|
4
8
|
}): Promise<any>;
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* INFO Fetch all Products
|
|
3
|
+
* used by the Products table in the admin panel
|
|
4
|
+
*/
|
|
5
|
+
declare function getTableProducts(currentPage: number, rowsPerPage: number, order: "asc" | "desc", orderBy: string, is_archive?: boolean[], // default to only non-archived OPOs
|
|
6
|
+
filters?: {
|
|
7
|
+
[key: string]: string;
|
|
8
|
+
}): Promise<any>;
|
|
9
|
+
export { getTableProducts };
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* INFO Fetch all IROs
|
|
3
|
+
* used by the IROs table in the admin panel
|
|
4
|
+
*/
|
|
5
|
+
declare function getAllIros(currentPage: number, rowsPerPage: number, order: "asc" | "desc", orderBy: string, is_archive?: boolean[], // default to only non-archived OPOs
|
|
6
|
+
filters?: {
|
|
7
|
+
[key: string]: string;
|
|
8
|
+
}): Promise<any>;
|
|
2
9
|
export { getAllIros };
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* INFO Fetch all IPOs
|
|
3
|
+
* used by the IPOs table in the admin panel
|
|
4
|
+
*/
|
|
5
|
+
declare function getTableIpos(currentPage: number, rowsPerPage: number, order: "asc" | "desc", orderBy: string, is_archive?: boolean[], // default to only non-archived OPOs
|
|
6
|
+
filters?: {
|
|
7
|
+
[key: string]: string;
|
|
8
|
+
}): Promise<any>;
|
|
9
|
+
export { getTableIpos };
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* INFO
|
|
3
|
+
* Flattens the attributes of a Strapi response object.
|
|
4
|
+
* @param data The Strapi response object to flatten.
|
|
5
|
+
* @returns The flattened object.
|
|
6
|
+
*/
|
|
1
7
|
export declare function flattenAttributes(data: any): any;
|
|
8
|
+
/**
|
|
9
|
+
* INFO
|
|
10
|
+
* @returns The base URL for the Strapi API, either from environment variables or a default value.
|
|
11
|
+
*/
|
|
2
12
|
export declare function getStrapiURL(): string;
|
|
3
13
|
export declare function getStrapiMedia(url: string | null): string | null;
|
|
4
14
|
export declare function setOpacity(color: string, opacity: number): string;
|
package/package.json
CHANGED
package/src/app/page.tsx
CHANGED
|
@@ -4,28 +4,34 @@ import qs from "qs";
|
|
|
4
4
|
import { fetchData } from "../loaders";
|
|
5
5
|
import { flattenAttributes, getStrapiURL } from "../../../lib/utils";
|
|
6
6
|
import { unstable_noStore as noStore } from "next/cache";
|
|
7
|
+
import { processFilters } from "../../../lib/processFilters";
|
|
7
8
|
|
|
8
9
|
const baseUrl = getStrapiURL();
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
async function getAllCustomers(
|
|
11
12
|
currentPage: number,
|
|
12
13
|
rowsPerPage: number,
|
|
13
14
|
order: "asc" | "desc",
|
|
14
|
-
orderBy: string
|
|
15
|
+
orderBy: string,
|
|
16
|
+
// is_archive: boolean[] = [false], // default to only non-archived OPOs
|
|
17
|
+
filters: { [key: string]: string } = {}
|
|
15
18
|
) {
|
|
16
19
|
noStore();
|
|
17
20
|
|
|
18
21
|
const url = new URL(`/api/customer-profiles`, baseUrl);
|
|
19
22
|
|
|
23
|
+
const processedFilters = processFilters(filters);
|
|
24
|
+
|
|
20
25
|
url.search = qs.stringify({
|
|
26
|
+
filters: {
|
|
27
|
+
// at this moment we don't have an is_archive field in customer profiles
|
|
28
|
+
// is_archive: {
|
|
29
|
+
// $in: is_archive,
|
|
30
|
+
// },
|
|
31
|
+
...processedFilters,
|
|
32
|
+
},
|
|
21
33
|
sort: `${orderBy || "id"}:${order || "desc"}`,
|
|
22
34
|
/* populate: {
|
|
23
|
-
price: true,
|
|
24
|
-
// image: true,
|
|
25
|
-
// gallery: true,
|
|
26
|
-
// dimensions: true,
|
|
27
|
-
// categories: true,
|
|
28
|
-
// brand: true,
|
|
29
35
|
}, */
|
|
30
36
|
pagination: {
|
|
31
37
|
pageSize: rowsPerPage || 10,
|
|
@@ -35,3 +41,5 @@ export async function getAllCustomers(
|
|
|
35
41
|
|
|
36
42
|
return await fetchData(url.href);
|
|
37
43
|
}
|
|
44
|
+
|
|
45
|
+
export { getAllCustomers };
|
|
@@ -4,21 +4,36 @@ import qs from "qs";
|
|
|
4
4
|
import { fetchData } from "../loaders";
|
|
5
5
|
import { flattenAttributes, getStrapiURL } from "../../../lib/utils";
|
|
6
6
|
import { unstable_noStore as noStore } from "next/cache";
|
|
7
|
+
import { processFilters } from "../../../lib/processFilters";
|
|
7
8
|
|
|
8
9
|
const baseUrl = getStrapiURL();
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* INFO Fetch all Invoices
|
|
13
|
+
* used by the Invoices table in the admin panel
|
|
14
|
+
*/
|
|
15
|
+
async function getAllInvoices(
|
|
11
16
|
currentPage: number,
|
|
12
17
|
rowsPerPage: number,
|
|
13
18
|
order: "asc" | "desc",
|
|
14
|
-
orderBy: string
|
|
19
|
+
orderBy: string,
|
|
20
|
+
is_archive: boolean[] = [false], // default to only non-archived OPOs
|
|
21
|
+
filters: { [key: string]: string } = {}
|
|
15
22
|
) {
|
|
16
23
|
noStore();
|
|
17
24
|
|
|
18
25
|
const url = new URL(`/api/invoices`, baseUrl);
|
|
19
26
|
|
|
27
|
+
const processedFilters = processFilters(filters);
|
|
28
|
+
|
|
20
29
|
url.search = qs.stringify({
|
|
21
|
-
|
|
30
|
+
filters: {
|
|
31
|
+
// at this moment we don't have an is_archive field in invoices
|
|
32
|
+
// is_archive: {
|
|
33
|
+
// $in: is_archive,
|
|
34
|
+
// },
|
|
35
|
+
...processedFilters,
|
|
36
|
+
},
|
|
22
37
|
sort: `${orderBy || "id"}:${order || "desc"}`,
|
|
23
38
|
populate: {
|
|
24
39
|
items: true,
|
|
@@ -41,3 +56,5 @@ export async function getAllInvoices(
|
|
|
41
56
|
|
|
42
57
|
return flattenAttributes(await fetchData(url.href));
|
|
43
58
|
}
|
|
59
|
+
|
|
60
|
+
export { getAllInvoices };
|
|
@@ -9,12 +9,16 @@ import { processFilters } from "../../../lib/processFilters";
|
|
|
9
9
|
|
|
10
10
|
const baseUrl = getStrapiURL();
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* INFO Fetch all OPOs
|
|
14
|
+
* used by the OPOs table in the admin panel
|
|
15
|
+
*/
|
|
12
16
|
async function getAllOpos(
|
|
13
17
|
currentPage: number,
|
|
14
18
|
rowsPerPage: number,
|
|
15
19
|
order: "asc" | "desc",
|
|
16
20
|
orderBy: string,
|
|
17
|
-
is_archive: boolean[] = [false], // default to
|
|
21
|
+
is_archive: boolean[] = [false], // default to only non-archived OPOs
|
|
18
22
|
filters: { [key: string]: string } = {}
|
|
19
23
|
) {
|
|
20
24
|
noStore();
|
|
@@ -24,6 +28,7 @@ async function getAllOpos(
|
|
|
24
28
|
const isEnduser = role === "enduser";
|
|
25
29
|
|
|
26
30
|
const url = new URL(`/api/opos`, baseUrl);
|
|
31
|
+
|
|
27
32
|
const processedFilters = processFilters(filters);
|
|
28
33
|
|
|
29
34
|
url.search = qs.stringify({
|
|
@@ -2,31 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
import qs from "qs";
|
|
4
4
|
import { fetchData } from "../loaders";
|
|
5
|
-
import {
|
|
5
|
+
import { getStrapiURL } from "../../../lib/utils";
|
|
6
6
|
import { unstable_noStore as noStore } from "next/cache";
|
|
7
|
-
|
|
8
|
-
// this is the get all product function for the backend, it should be universal so it also works on the frontend
|
|
9
|
-
// this function is based on get all orders which the frontenduser uses to get all orders in it's order table
|
|
7
|
+
import { processFilters } from "../../../lib/processFilters";
|
|
10
8
|
|
|
11
9
|
const baseUrl = getStrapiURL();
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
/**
|
|
12
|
+
* INFO Fetch all Products
|
|
13
|
+
* used by the Products table in the admin panel
|
|
14
|
+
*/
|
|
15
|
+
async function getTableProducts(
|
|
14
16
|
currentPage: number,
|
|
15
17
|
rowsPerPage: number,
|
|
16
18
|
order: "asc" | "desc",
|
|
17
19
|
orderBy: string,
|
|
18
|
-
is_archive: boolean[]
|
|
19
|
-
|
|
20
|
+
is_archive: boolean[] = [false], // default to only non-archived OPOs
|
|
21
|
+
filters: { [key: string]: string } = {}
|
|
20
22
|
) {
|
|
21
23
|
noStore();
|
|
22
24
|
|
|
23
25
|
const url = new URL(`/api/products`, baseUrl);
|
|
24
26
|
|
|
27
|
+
const processedFilters = processFilters(filters);
|
|
28
|
+
|
|
25
29
|
url.search = qs.stringify({
|
|
26
30
|
filters: {
|
|
27
31
|
is_archive: {
|
|
28
32
|
$in: is_archive,
|
|
29
33
|
},
|
|
34
|
+
...processedFilters,
|
|
30
35
|
},
|
|
31
36
|
sort: `${orderBy || "id"}:${order || "desc"}`,
|
|
32
37
|
populate: {
|
|
@@ -45,3 +50,5 @@ export async function getTableProducts(
|
|
|
45
50
|
|
|
46
51
|
return await fetchData(url.href);
|
|
47
52
|
}
|
|
53
|
+
|
|
54
|
+
export { getTableProducts };
|
|
@@ -5,15 +5,21 @@ import { fetchData } from "../../loaders";
|
|
|
5
5
|
import { getStrapiURL } from "../../../../lib/utils";
|
|
6
6
|
import { unstable_noStore as noStore } from "next/cache";
|
|
7
7
|
import { getUserRole } from "../../../services/get-user-me-loader";
|
|
8
|
+
import { processFilters } from "../../../../lib/processFilters";
|
|
8
9
|
|
|
9
10
|
const baseUrl = getStrapiURL();
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* INFO Fetch all IROs
|
|
14
|
+
* used by the IROs table in the admin panel
|
|
15
|
+
*/
|
|
11
16
|
async function getAllIros(
|
|
12
17
|
currentPage: number,
|
|
13
18
|
rowsPerPage: number,
|
|
14
19
|
order: "asc" | "desc",
|
|
15
20
|
orderBy: string,
|
|
16
|
-
is_archive: boolean[]
|
|
21
|
+
is_archive: boolean[] = [false], // default to only non-archived OPOs
|
|
22
|
+
filters: { [key: string]: string } = {}
|
|
17
23
|
) {
|
|
18
24
|
noStore();
|
|
19
25
|
|
|
@@ -23,11 +29,14 @@ async function getAllIros(
|
|
|
23
29
|
|
|
24
30
|
const url = new URL(`/api/iros`, baseUrl);
|
|
25
31
|
|
|
32
|
+
const processedFilters = processFilters(filters);
|
|
33
|
+
|
|
26
34
|
url.search = qs.stringify({
|
|
27
35
|
filters: {
|
|
28
36
|
is_archive: {
|
|
29
37
|
$in: is_archive,
|
|
30
38
|
},
|
|
39
|
+
...processedFilters,
|
|
31
40
|
},
|
|
32
41
|
sort: `${orderBy || "id"}:${order || "desc"}`,
|
|
33
42
|
populate: {
|
|
@@ -5,18 +5,21 @@ import { fetchData } from "../loaders";
|
|
|
5
5
|
import { getStrapiURL } from "../../../lib/utils";
|
|
6
6
|
import { unstable_noStore as noStore } from "next/cache";
|
|
7
7
|
import { getUserRole } from "../../services/get-user-me-loader";
|
|
8
|
-
|
|
9
|
-
// this is the get all product function for the backend, it should be universal so it also works on the frontend
|
|
10
|
-
// this function is based on get all orders which the frontenduser uses to get all orders in it's order table
|
|
8
|
+
import { processFilters } from "../../../lib/processFilters";
|
|
11
9
|
|
|
12
10
|
const baseUrl = getStrapiURL();
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
/**
|
|
13
|
+
* INFO Fetch all IPOs
|
|
14
|
+
* used by the IPOs table in the admin panel
|
|
15
|
+
*/
|
|
16
|
+
async function getTableIpos(
|
|
15
17
|
currentPage: number,
|
|
16
18
|
rowsPerPage: number,
|
|
17
19
|
order: "asc" | "desc",
|
|
18
20
|
orderBy: string,
|
|
19
|
-
is_archive: boolean[]
|
|
21
|
+
is_archive: boolean[] = [false], // default to only non-archived OPOs
|
|
22
|
+
filters: { [key: string]: string } = {}
|
|
20
23
|
) {
|
|
21
24
|
noStore();
|
|
22
25
|
|
|
@@ -26,11 +29,14 @@ export async function getTableIpos(
|
|
|
26
29
|
|
|
27
30
|
const url = new URL(`/api/ipos`, baseUrl);
|
|
28
31
|
|
|
32
|
+
const processedFilters = processFilters(filters);
|
|
33
|
+
|
|
29
34
|
url.search = qs.stringify({
|
|
30
35
|
filters: {
|
|
31
36
|
is_archive: {
|
|
32
37
|
$in: is_archive,
|
|
33
38
|
},
|
|
39
|
+
...processedFilters,
|
|
34
40
|
},
|
|
35
41
|
sort: `${orderBy || "id"}:${order || "desc"}`,
|
|
36
42
|
populate: {
|
|
@@ -49,7 +55,6 @@ export async function getTableIpos(
|
|
|
49
55
|
},
|
|
50
56
|
},
|
|
51
57
|
},
|
|
52
|
-
|
|
53
58
|
pagination: {
|
|
54
59
|
pageSize: rowsPerPage || 10,
|
|
55
60
|
page: currentPage ? currentPage + 1 : 1, // because table pagination starts at 0 but strapi starts at 1
|
|
@@ -58,3 +63,5 @@ export async function getTableIpos(
|
|
|
58
63
|
|
|
59
64
|
return await fetchData(url.href);
|
|
60
65
|
}
|
|
66
|
+
|
|
67
|
+
export { getTableIpos };
|
package/src/lib/utils.ts
CHANGED
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
// return twMerge(clsx(inputs));
|
|
6
6
|
// }
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* INFO
|
|
10
|
+
* Flattens the attributes of a Strapi response object.
|
|
11
|
+
* @param data The Strapi response object to flatten.
|
|
12
|
+
* @returns The flattened object.
|
|
13
|
+
*/
|
|
8
14
|
export function flattenAttributes(data: any): any {
|
|
9
15
|
// Check if data is a plain object; return as is if not
|
|
10
16
|
if (
|
|
@@ -45,6 +51,10 @@ export function flattenAttributes(data: any): any {
|
|
|
45
51
|
return flattened;
|
|
46
52
|
}
|
|
47
53
|
|
|
54
|
+
/**
|
|
55
|
+
* INFO
|
|
56
|
+
* @returns The base URL for the Strapi API, either from environment variables or a default value.
|
|
57
|
+
*/
|
|
48
58
|
export function getStrapiURL() {
|
|
49
59
|
return process.env.NEXT_PUBLIC_STRAPI_URL ?? "http://localhost:1337";
|
|
50
60
|
}
|
package/.ai/action-patterns.md
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
# Action Patterns
|
|
2
|
-
|
|
3
|
-
## Server Action Parameter Pattern
|
|
4
|
-
|
|
5
|
-
### Setup
|
|
6
|
-
|
|
7
|
-
1. Action Definition:
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
export async function updateEntityAction(
|
|
11
|
-
id: EntityId, // Entity identifier first
|
|
12
|
-
prevState: any, // Form state second
|
|
13
|
-
formData: FormData // Form data last
|
|
14
|
-
) {
|
|
15
|
-
// action implementation
|
|
16
|
-
}
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
2. Form Implementation:
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
const boundAction = updateEntityAction.bind(null, entityId);
|
|
23
|
-
const [formState, formAction] = useFormState(boundAction, INITIAL_STATE);
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Implementation Pattern
|
|
27
|
-
|
|
28
|
-
1. Action Structure:
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
export async function updateEntityAction(
|
|
32
|
-
id: number,
|
|
33
|
-
prevState: any,
|
|
34
|
-
formData: FormData
|
|
35
|
-
) {
|
|
36
|
-
// 1. Parse form data if needed
|
|
37
|
-
const parsedData = parseFormData(formData);
|
|
38
|
-
|
|
39
|
-
// 2. Call API or service
|
|
40
|
-
const responseData = await mutateData(
|
|
41
|
-
"PUT",
|
|
42
|
-
`/api/entities/${id}`,
|
|
43
|
-
parsedData
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
// 3. Handle error cases
|
|
47
|
-
if (!responseData) {
|
|
48
|
-
return {
|
|
49
|
-
...prevState,
|
|
50
|
-
severity: "error",
|
|
51
|
-
strapiErrors: null,
|
|
52
|
-
message: "Operation failed. Please try again.",
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// 4. Return success result
|
|
57
|
-
return {
|
|
58
|
-
...prevState,
|
|
59
|
-
severity: "success",
|
|
60
|
-
message: "Operation completed successfully",
|
|
61
|
-
data: responseData,
|
|
62
|
-
strapiErrors: null,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Key Features
|
|
68
|
-
|
|
69
|
-
1. **Parameter Order by Action Type**:
|
|
70
|
-
|
|
71
|
-
For Update Actions:
|
|
72
|
-
|
|
73
|
-
- Entity identifiers come first (id, uuid, etc.)
|
|
74
|
-
- prevState is always second
|
|
75
|
-
- formData is always last
|
|
76
|
-
|
|
77
|
-
For Create Actions:
|
|
78
|
-
|
|
79
|
-
- prevState is always first
|
|
80
|
-
- formData is always second
|
|
81
|
-
- No entity identifiers needed
|
|
82
|
-
|
|
83
|
-
2. **Action Binding**:
|
|
84
|
-
|
|
85
|
-
- Only used for update operations on specific entities
|
|
86
|
-
- Use Function.bind() to pre-fill entity parameters
|
|
87
|
-
- Bind with null as first argument
|
|
88
|
-
- Not needed for creation actions
|
|
89
|
-
|
|
90
|
-
3. **Response Structure**:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
{
|
|
94
|
-
...prevState, // Always preserve previous state
|
|
95
|
-
severity: string, // "success" | "error"
|
|
96
|
-
message: string, // User-friendly message
|
|
97
|
-
data?: any, // Optional updated entity data
|
|
98
|
-
strapiErrors?: any // Optional Strapi error details
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Best Practices
|
|
103
|
-
|
|
104
|
-
1. **Error Handling**:
|
|
105
|
-
|
|
106
|
-
- Always return prevState spread first
|
|
107
|
-
- Include user-friendly error messages
|
|
108
|
-
- Provide appropriate severity levels
|
|
109
|
-
- Handle API errors consistently
|
|
110
|
-
|
|
111
|
-
2. **Success Handling**:
|
|
112
|
-
|
|
113
|
-
- Return updated data when available
|
|
114
|
-
- Clear error states on success
|
|
115
|
-
- Set appropriate success message
|
|
116
|
-
- Use "success" severity
|
|
117
|
-
|
|
118
|
-
3. **Code Organization**:
|
|
119
|
-
|
|
120
|
-
- Group related actions in feature folders
|
|
121
|
-
- Use consistent file naming (e.g., updateEntityAction.ts)
|
|
122
|
-
- Export actions as named exports
|
|
123
|
-
- Include proper TypeScript types
|
|
124
|
-
|
|
125
|
-
## Server Action Types
|
|
126
|
-
|
|
127
|
-
### 1. Entity Update Actions
|
|
128
|
-
|
|
129
|
-
These actions modify an existing entity and therefore require the entity ID as
|
|
130
|
-
the first parameter.
|
|
131
|
-
|
|
132
|
-
1. Action Definition:
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
export async function updateEntityAction(
|
|
136
|
-
id: EntityId, // Entity identifier first
|
|
137
|
-
prevState: any, // Form state second
|
|
138
|
-
formData: FormData // Form data last
|
|
139
|
-
) {
|
|
140
|
-
// action implementation
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
2. Form Implementation:
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
const boundAction = updateEntityAction.bind(null, entityId);
|
|
148
|
-
const [formState, formAction] = useFormState(boundAction, INITIAL_STATE);
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### 2. Entity Creation Actions
|
|
152
|
-
|
|
153
|
-
These actions create new entities and don't require pre-bound parameters.
|
|
154
|
-
|
|
155
|
-
1. Action Definition:
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
export async function createEntityAction(
|
|
159
|
-
prevState: any, // Form state first
|
|
160
|
-
formData: FormData // Form data second
|
|
161
|
-
) {
|
|
162
|
-
// action implementation
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
2. Form Implementation:
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
const [formState, formAction] = useFormState(createEntityAction, INITIAL_STATE);
|
|
170
|
-
```
|
|
File without changes
|