@iservice365/layer-common 0.0.1
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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.editorconfig +12 -0
- package/.github/workflows/main.yml +17 -0
- package/.github/workflows/publish.yml +39 -0
- package/.nuxtrc +1 -0
- package/.playground/app.vue +36 -0
- package/.playground/eslint.config.mjs +6 -0
- package/.playground/nuxt.config.ts +22 -0
- package/CHANGELOG.md +8 -0
- package/README.md +73 -0
- package/app.vue +3 -0
- package/components/BtnUploadFile.vue +139 -0
- package/components/Input/Date.vue +177 -0
- package/components/Input/Password.vue +22 -0
- package/components/InputLabel.vue +18 -0
- package/components/Layout/Header.vue +248 -0
- package/components/Layout/NavigationDrawer.vue +24 -0
- package/components/ListItem.vue +35 -0
- package/components/LocalPagination.vue +31 -0
- package/components/NavigationItem.vue +59 -0
- package/components/PlaceholderComponent.vue +34 -0
- package/components/Snackbar.vue +23 -0
- package/composables/useLocal.ts +41 -0
- package/composables/useLocalAuth.ts +109 -0
- package/composables/useOrg.ts +127 -0
- package/composables/usePermission.ts +54 -0
- package/composables/useRecapPermission.ts +26 -0
- package/composables/useRole.ts +73 -0
- package/composables/useUser.ts +93 -0
- package/composables/useUtils.ts +109 -0
- package/nuxt.config.ts +60 -0
- package/package.json +33 -0
- package/plugins/API.ts +44 -0
- package/plugins/vuetify.ts +41 -0
- package/tsconfig.json +3 -0
- package/types/local.d.ts +63 -0
- package/types/permission.d.ts +24 -0
- package/types/role.d.ts +11 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import useUtils from "./useUtils";
|
|
2
|
+
|
|
3
|
+
export default function useOrg() {
|
|
4
|
+
const org = useState("organization", (): TOrg => {
|
|
5
|
+
return {
|
|
6
|
+
_id: "",
|
|
7
|
+
name: "",
|
|
8
|
+
email: "",
|
|
9
|
+
busInst: "",
|
|
10
|
+
owner: "",
|
|
11
|
+
type: "",
|
|
12
|
+
createdAt: "",
|
|
13
|
+
updatedAt: "",
|
|
14
|
+
status: "",
|
|
15
|
+
deletedAt: "",
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
function setOrg(value?: Partial<TOrg>) {
|
|
20
|
+
if (!value) {
|
|
21
|
+
value = {
|
|
22
|
+
_id: "",
|
|
23
|
+
name: "",
|
|
24
|
+
email: "",
|
|
25
|
+
busInst: "",
|
|
26
|
+
owner: "",
|
|
27
|
+
type: "",
|
|
28
|
+
createdAt: "",
|
|
29
|
+
updatedAt: "",
|
|
30
|
+
status: "",
|
|
31
|
+
deletedAt: "",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
org.value._id = value._id;
|
|
36
|
+
org.value.name = value.name ?? "";
|
|
37
|
+
org.value.email = value.email ?? "";
|
|
38
|
+
org.value.busInst = value.busInst ?? "";
|
|
39
|
+
org.value.owner = value.owner ?? "";
|
|
40
|
+
org.value.type = value.type ?? "";
|
|
41
|
+
org.value.createdAt = value.createdAt;
|
|
42
|
+
org.value.updatedAt = value.updatedAt;
|
|
43
|
+
org.value.status = value.status ?? "";
|
|
44
|
+
org.value.deletedAt = value.deletedAt ?? "";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function createOrg(value: Partial<TOrg>) {
|
|
48
|
+
delete value.createdAt;
|
|
49
|
+
delete value.updatedAt;
|
|
50
|
+
delete value._id;
|
|
51
|
+
delete value.status;
|
|
52
|
+
|
|
53
|
+
return useNuxtApp().$api("/api/orgs", {
|
|
54
|
+
method: "POST",
|
|
55
|
+
body: JSON.stringify(value),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getOrgs({ search = "", page = 1 } = {}) {
|
|
60
|
+
return useNuxtApp().$api<TKeyValuePair>("/api/orgs", {
|
|
61
|
+
method: "GET",
|
|
62
|
+
query: { search, page },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function updateOrgField(_id = "", field = "", value = "") {
|
|
67
|
+
return useNuxtApp().$api<TKeyValuePair>(`/api/orgs/field/${_id}`, {
|
|
68
|
+
method: "PATCH",
|
|
69
|
+
body: { field, value },
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const page = useState("orgPage", () => 1);
|
|
74
|
+
const pages = useState("orgPages", () => 0);
|
|
75
|
+
const pageRange = useState("orgPageRange", () => "0-0 of 0");
|
|
76
|
+
|
|
77
|
+
function getOrgById(id = "") {
|
|
78
|
+
return useNuxtApp().$api<TOrg>(`/api/orgs/id/${id}`, {
|
|
79
|
+
method: "GET",
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const selectedOrg = useState("selectedOrg", () => "");
|
|
84
|
+
|
|
85
|
+
const myOrgs = useState("myOrgs", (): Array<TOrgsAsOption> => []);
|
|
86
|
+
|
|
87
|
+
const { debounce } = useUtils();
|
|
88
|
+
|
|
89
|
+
const getOrgsByUser = debounce(async (user = "") => {
|
|
90
|
+
try {
|
|
91
|
+
const res = await useNuxtApp().$api<Array<TOrgsAsOption>>(
|
|
92
|
+
`/api/orgs/user/${user}`,
|
|
93
|
+
{
|
|
94
|
+
method: "GET",
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
myOrgs.value = res;
|
|
98
|
+
} catch (error) {
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}, 1000);
|
|
102
|
+
|
|
103
|
+
const theOrg = computed(() => {
|
|
104
|
+
return myOrgs.value.find((i) => i.value === selectedOrg.value);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const otherOrgs = computed(() => {
|
|
108
|
+
return myOrgs.value.filter((i) => i.value !== selectedOrg.value);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
org,
|
|
113
|
+
setOrg,
|
|
114
|
+
createOrg,
|
|
115
|
+
getOrgs,
|
|
116
|
+
page,
|
|
117
|
+
pages,
|
|
118
|
+
pageRange,
|
|
119
|
+
getOrgById,
|
|
120
|
+
selectedOrg,
|
|
121
|
+
myOrgs,
|
|
122
|
+
getOrgsByUser,
|
|
123
|
+
theOrg,
|
|
124
|
+
otherOrgs,
|
|
125
|
+
updateOrgField,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export default function usePermission() {
|
|
2
|
+
// Permission-Based Access Control with Dynamic Role Creation
|
|
3
|
+
|
|
4
|
+
// Utility to list all resources and their actions
|
|
5
|
+
function listPermissions(permissions: TPermissions): {
|
|
6
|
+
resource: string;
|
|
7
|
+
actions: { title: string; description: string }[];
|
|
8
|
+
}[] {
|
|
9
|
+
return Object.entries(permissions).map(([resource, actions]) => ({
|
|
10
|
+
resource,
|
|
11
|
+
actions: Object.entries(actions).map(([action, { description }]) => ({
|
|
12
|
+
title: action,
|
|
13
|
+
description,
|
|
14
|
+
})),
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Utility to check if a user has permission
|
|
19
|
+
function hasPermission(
|
|
20
|
+
user: TRole,
|
|
21
|
+
permissions: TPermissions,
|
|
22
|
+
resource: string,
|
|
23
|
+
action: string,
|
|
24
|
+
data?: any
|
|
25
|
+
): boolean {
|
|
26
|
+
const permissionKey = `${resource}:${action}`;
|
|
27
|
+
|
|
28
|
+
// Check if the permission exists in the user's permission array
|
|
29
|
+
if (!user.permissions?.includes(permissionKey)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const resourcePermissions = permissions[resource];
|
|
34
|
+
if (!resourcePermissions || !resourcePermissions[action]) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const permissionCheck = resourcePermissions[action].check;
|
|
39
|
+
|
|
40
|
+
// Evaluate the permission check
|
|
41
|
+
if (typeof permissionCheck === "boolean") {
|
|
42
|
+
return permissionCheck;
|
|
43
|
+
} else if (typeof permissionCheck === "function") {
|
|
44
|
+
return permissionCheck(user, data);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
listPermissions,
|
|
52
|
+
hasPermission,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default function useRecapPermission() {
|
|
2
|
+
const permissions: TPermissions = {
|
|
3
|
+
request: {
|
|
4
|
+
"create-request": {
|
|
5
|
+
check: true,
|
|
6
|
+
description: "Create a new request.",
|
|
7
|
+
},
|
|
8
|
+
"review-request": {
|
|
9
|
+
check: true,
|
|
10
|
+
description: "Review a request.",
|
|
11
|
+
},
|
|
12
|
+
"approve-request": {
|
|
13
|
+
check: true,
|
|
14
|
+
description: "Approve a request.",
|
|
15
|
+
},
|
|
16
|
+
"delete-request": {
|
|
17
|
+
check: true,
|
|
18
|
+
description: "Delete authored request.",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
permissions,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export default function useRole() {
|
|
2
|
+
function createRole(
|
|
3
|
+
{ name, permissions, type } = {} as {
|
|
4
|
+
name: string;
|
|
5
|
+
permissions: Array<string>;
|
|
6
|
+
type: string;
|
|
7
|
+
}
|
|
8
|
+
) {
|
|
9
|
+
return useNuxtApp().$api("/api/roles", {
|
|
10
|
+
method: "POST",
|
|
11
|
+
body: { name, permissions, type },
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getRoles({ search = "", page = 1, limit = 20, type = "" } = {}) {
|
|
16
|
+
return useNuxtApp().$api<TKeyValuePair>("/api/roles", {
|
|
17
|
+
method: "GET",
|
|
18
|
+
query: { search, page, limit, type },
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getRoleById(id: string) {
|
|
23
|
+
return useNuxtApp().$api<TKeyValuePair>(`/api/roles/id/${id}`, {
|
|
24
|
+
method: "GET",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function updateRoleById(
|
|
29
|
+
_id: string,
|
|
30
|
+
name?: string,
|
|
31
|
+
permissions?: Array<string>
|
|
32
|
+
) {
|
|
33
|
+
return useNuxtApp().$api(`/api/roles/id/${_id}`, {
|
|
34
|
+
method: "PATCH",
|
|
35
|
+
body: { name, permissions },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function updateRoleFieldById(_id: string, field: string, value: string) {
|
|
40
|
+
return useNuxtApp().$api(`/api/roles/${_id}`, {
|
|
41
|
+
method: "PATCH",
|
|
42
|
+
body: { field, value },
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function deleteRole(_id: string) {
|
|
47
|
+
return useNuxtApp().$api(`/api/roles/${_id}`, {
|
|
48
|
+
method: "DELETE",
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const role = useState<TRole>("userRole", () => {
|
|
53
|
+
return {
|
|
54
|
+
_id: "",
|
|
55
|
+
name: "",
|
|
56
|
+
permissions: [],
|
|
57
|
+
description: "",
|
|
58
|
+
createdAt: "",
|
|
59
|
+
updatedAt: "",
|
|
60
|
+
deletedAt: "",
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
role,
|
|
66
|
+
createRole,
|
|
67
|
+
getRoles,
|
|
68
|
+
getRoleById,
|
|
69
|
+
updateRoleById,
|
|
70
|
+
updateRoleFieldById,
|
|
71
|
+
deleteRole,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export default function useUser() {
|
|
2
|
+
function inviteUser({ email = "", app = "", role = "", name = "" } = {}) {
|
|
3
|
+
return useNuxtApp().$api<TKeyValuePair>("/api/auth/invite", {
|
|
4
|
+
method: "POST",
|
|
5
|
+
body: { email, app, role, name },
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function updateName({ firstName = "", lastName = "" } = {}) {
|
|
10
|
+
return useNuxtApp().$api<TKeyValuePair>("/api/users/name", {
|
|
11
|
+
method: "PUT",
|
|
12
|
+
body: { firstName, lastName },
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function updateBirthday({ month = "", day = 0, year = 0 } = {}) {
|
|
17
|
+
return useNuxtApp().$api<TKeyValuePair>("/api/users/birthday", {
|
|
18
|
+
method: "PUT",
|
|
19
|
+
body: { month, day, year },
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function updateGender(gender = "") {
|
|
24
|
+
return useNuxtApp().$api<TKeyValuePair>("/api/users/gender", {
|
|
25
|
+
method: "PUT",
|
|
26
|
+
body: { gender },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function updateEmail(email = "") {
|
|
31
|
+
return useNuxtApp().$api<TKeyValuePair>("/api/users/email", {
|
|
32
|
+
method: "PUT",
|
|
33
|
+
body: { email },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function updateContact(contact = "") {
|
|
38
|
+
return useNuxtApp().$api<TKeyValuePair>("/api/users/contact", {
|
|
39
|
+
method: "PUT",
|
|
40
|
+
body: { contact },
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function updateUserFieldById(id = "", field = "", value = "") {
|
|
45
|
+
return useNuxtApp().$api<TKeyValuePair>(`/api/users/field/${id}`, {
|
|
46
|
+
method: "PATCH",
|
|
47
|
+
body: { field, value },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getUsers({
|
|
52
|
+
status = "active",
|
|
53
|
+
type = "",
|
|
54
|
+
search = "",
|
|
55
|
+
page = 1,
|
|
56
|
+
} = {}) {
|
|
57
|
+
return useNuxtApp().$api<TKeyValuePair>("/api/users", {
|
|
58
|
+
method: "GET",
|
|
59
|
+
query: { status, search, page, type },
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getById(id = "") {
|
|
64
|
+
return useNuxtApp().$api<TKeyValuePair>(`/api/users/id/${id}`, {
|
|
65
|
+
method: "GET",
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function createUserByInvite({
|
|
70
|
+
firstName = "",
|
|
71
|
+
lastName = "",
|
|
72
|
+
password = "",
|
|
73
|
+
id = "",
|
|
74
|
+
} = {}) {
|
|
75
|
+
return useNuxtApp().$api<TKeyValuePair>(`/api/users/invite/${id}`, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
body: { firstName, lastName, password },
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
inviteUser,
|
|
83
|
+
updateName,
|
|
84
|
+
updateBirthday,
|
|
85
|
+
updateGender,
|
|
86
|
+
updateEmail,
|
|
87
|
+
updateContact,
|
|
88
|
+
updateUserFieldById,
|
|
89
|
+
getUsers,
|
|
90
|
+
createUserByInvite,
|
|
91
|
+
getById,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export default function useUtils() {
|
|
2
|
+
const requiredRule = (v: string) => !!v || "Required";
|
|
3
|
+
|
|
4
|
+
const emailRule = (v: string): true | string => {
|
|
5
|
+
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
6
|
+
return regex.test(v) || "Please enter a valid email address";
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const passwordRule = (v: string) =>
|
|
10
|
+
v.length >= 8 || "Password must be at least 8 characters long";
|
|
11
|
+
|
|
12
|
+
const confirmPasswordRule =
|
|
13
|
+
(newPassword: Ref<string>, confirmPassword: Ref<string>) => () =>
|
|
14
|
+
confirmPassword.value === newPassword.value || "Passwords must match";
|
|
15
|
+
|
|
16
|
+
const validateEmail = (email: Ref<string>, emailErrors: Ref<string[]>) => {
|
|
17
|
+
emailErrors.value = [];
|
|
18
|
+
|
|
19
|
+
if (!email.value) {
|
|
20
|
+
emailErrors.value.push("Please input your email");
|
|
21
|
+
} else {
|
|
22
|
+
const result = emailRule(email.value);
|
|
23
|
+
if (result !== true) {
|
|
24
|
+
emailErrors.value.push(result);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const validatePassword = (
|
|
30
|
+
password: Ref<string>,
|
|
31
|
+
passwordErrors: Ref<string[]>
|
|
32
|
+
) => {
|
|
33
|
+
passwordErrors.value = [];
|
|
34
|
+
|
|
35
|
+
if (!password.value) {
|
|
36
|
+
passwordErrors.value.push("Please input your password");
|
|
37
|
+
} else if (!passwordRule(password.value)) {
|
|
38
|
+
passwordErrors.value.push("Password must be at least 8 characters long");
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function back() {
|
|
43
|
+
useRouter().back();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function debounce<T extends (...args: any[]) => void>(
|
|
47
|
+
func: T,
|
|
48
|
+
wait: number
|
|
49
|
+
): (...args: Parameters<T>) => void {
|
|
50
|
+
let timeoutId: ReturnType<typeof setTimeout>;
|
|
51
|
+
|
|
52
|
+
return function (...args: Parameters<T>) {
|
|
53
|
+
clearTimeout(timeoutId);
|
|
54
|
+
timeoutId = setTimeout(() => func(...args), wait);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function insertBetween(arr: any, elementToInsert: any) {
|
|
59
|
+
return arr.flatMap((item: any, index: number, array: any) =>
|
|
60
|
+
index < array.length - 1 ? [item, elementToInsert] : [item]
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getNameInitials(name: string) {
|
|
65
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
66
|
+
return ""; // Default fallback for invalid input
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const initials = name
|
|
70
|
+
.trim()
|
|
71
|
+
.split(/\s+/) // Split by spaces
|
|
72
|
+
.map((word) => word[0]?.toUpperCase()) // Take the first letter of each word and capitalize
|
|
73
|
+
.join(""); // Combine all initials
|
|
74
|
+
|
|
75
|
+
return initials.slice(0, 2); // Limit to 2 characters
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getDimensions(
|
|
79
|
+
file: File
|
|
80
|
+
): Promise<{ width: number; height: number }> {
|
|
81
|
+
const img = new Image();
|
|
82
|
+
img.src = URL.createObjectURL(file);
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
img.onload = () => {
|
|
85
|
+
const width = img.width;
|
|
86
|
+
const height = img.height;
|
|
87
|
+
resolve({ width, height });
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
img.onerror = () => {
|
|
91
|
+
reject(new Error("Failed to read image dimensions"));
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
requiredRule,
|
|
98
|
+
emailRule,
|
|
99
|
+
passwordRule,
|
|
100
|
+
confirmPasswordRule,
|
|
101
|
+
validateEmail,
|
|
102
|
+
validatePassword,
|
|
103
|
+
back,
|
|
104
|
+
debounce,
|
|
105
|
+
insertBetween,
|
|
106
|
+
getNameInitials,
|
|
107
|
+
getDimensions,
|
|
108
|
+
};
|
|
109
|
+
}
|
package/nuxt.config.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// https://nuxt.com/docs/api/configuration/nuxt-config
|
|
2
|
+
import vuetify, { transformAssetUrls } from "vite-plugin-vuetify";
|
|
3
|
+
export default defineNuxtConfig({
|
|
4
|
+
devtools: { enabled: true },
|
|
5
|
+
build: {
|
|
6
|
+
transpile: ["vuetify"],
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
runtimeConfig: {
|
|
10
|
+
public: {
|
|
11
|
+
cookieConfig: {
|
|
12
|
+
domain: (process.env.DOMAIN as string) ?? "localhost",
|
|
13
|
+
secure: true,
|
|
14
|
+
maxAge: 30 * 24 * 60 * 60,
|
|
15
|
+
},
|
|
16
|
+
APP_NAME: (process.env.APP_NAME as string) ?? "App",
|
|
17
|
+
APP_NAME_ROUTE: (process.env.APP_NAME_ROUTE as string) ?? "index",
|
|
18
|
+
APP_ACCOUNT: (process.env.APP_ACCOUNT as string) ?? "",
|
|
19
|
+
APP_PROJECT: (process.env.APP_PROJECT as string) ?? "",
|
|
20
|
+
APP_DEPED_HQ: (process.env.APP_DEPED_HQ as string) ?? "",
|
|
21
|
+
APP_REGION_HQ: (process.env.APP_REGION_HQ as string) ?? "",
|
|
22
|
+
APP_DIVISION_HQ: (process.env.APP_DIVISION_HQ as string) ?? "",
|
|
23
|
+
APP_SCHOOL_HQ: (process.env.APP_SCHOOL_HQ as string) ?? "",
|
|
24
|
+
APP_STUDENT_ZONE: (process.env.APP_STUDENT_ZONE as string) ?? "",
|
|
25
|
+
APP_PARENT_PORTAL: (process.env.APP_PARENT_PORTAL as string) ?? "",
|
|
26
|
+
APP_BOOK_KEEPING: (process.env.APP_BOOK_KEEPING as string) ?? "",
|
|
27
|
+
APP_ASSET_MANAGEMENT: (process.env.APP_ASSET as string) ?? "",
|
|
28
|
+
APP_EMPLOYEE_MANAGEMENT:
|
|
29
|
+
(process.env.APP_EMPLOYEE_MANAGEMENT as string) ?? "",
|
|
30
|
+
APP_PAYROLL: (process.env.APP_PAYROLL as string) ?? "",
|
|
31
|
+
APP_ATTENDANCE_KEEPING:
|
|
32
|
+
(process.env.APP_ATTENDANCE_KEEPING as string) ?? "",
|
|
33
|
+
APP_LEAVE_MANAGEMENT: (process.env.APP_LEAVE_MANAGEMENT as string) ?? "",
|
|
34
|
+
APP_PROPERTY_MANAGEMENT:
|
|
35
|
+
(process.env.APP_PROPERTY_MANAGEMENT as string) ?? "",
|
|
36
|
+
APP_RECRUITMENT: (process.env.APP_RECRUITMENT as string) ?? "",
|
|
37
|
+
API_DO_STORAGE_ENDPOINT:
|
|
38
|
+
(process.env.API_DO_STORAGE_ENDPOINT as string) ?? "",
|
|
39
|
+
APP_ADMIN: (process.env.APP_ADMIN as string) ?? "",
|
|
40
|
+
APP_RECAP: (process.env.APP_RECAP as string) ?? "",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
modules: [
|
|
45
|
+
(_options, nuxt) => {
|
|
46
|
+
nuxt.hooks.hook("vite:extendConfig", (config) => {
|
|
47
|
+
// @ts-expect-error
|
|
48
|
+
config.plugins.push(vuetify({ autoImport: true }));
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
|
|
53
|
+
vite: {
|
|
54
|
+
vue: {
|
|
55
|
+
template: {
|
|
56
|
+
transformAssetUrls,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iservice365/layer-common",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "0.0.1",
|
|
6
|
+
"main": "./nuxt.config.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "nuxi dev .playground",
|
|
12
|
+
"dev:prepare": "nuxt prepare .playground",
|
|
13
|
+
"build": "nuxt build .playground",
|
|
14
|
+
"generate": "nuxt generate .playground",
|
|
15
|
+
"preview": "nuxt preview .playground",
|
|
16
|
+
"release": "yarn run build && changeset publish"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@changesets/cli": "^2.27.9",
|
|
20
|
+
"@nuxt/eslint": "latest",
|
|
21
|
+
"eslint": "^9.14.0",
|
|
22
|
+
"nuxt": "^3.13.2",
|
|
23
|
+
"typescript": "^5.6.3",
|
|
24
|
+
"vite-plugin-vuetify": "^2.0.4",
|
|
25
|
+
"vue": "latest",
|
|
26
|
+
"vuetify": "^3.7.3"
|
|
27
|
+
},
|
|
28
|
+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@mdi/font": "^7.4.47",
|
|
31
|
+
"sass": "^1.80.6"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/plugins/API.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export default defineNuxtPlugin(() => {
|
|
2
|
+
const { cookieConfig } = useRuntimeConfig().public;
|
|
3
|
+
|
|
4
|
+
const api = $fetch.create({
|
|
5
|
+
baseURL: "/",
|
|
6
|
+
retry: 1,
|
|
7
|
+
retryStatusCodes: [401],
|
|
8
|
+
retryDelay: 500,
|
|
9
|
+
onRequest({ options }) {
|
|
10
|
+
const accessToken = useCookie("accessToken", cookieConfig).value;
|
|
11
|
+
options.headers = accessToken
|
|
12
|
+
? { Authorization: `Bearer ${accessToken}` }
|
|
13
|
+
: {};
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
async onResponseError({ response }) {
|
|
17
|
+
if (response.status === 401) {
|
|
18
|
+
await $fetch("/api/auth", {
|
|
19
|
+
baseURL: "/",
|
|
20
|
+
method: "PUT",
|
|
21
|
+
server: false,
|
|
22
|
+
credentials: "include",
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
token: useCookie("refreshToken", cookieConfig).value,
|
|
25
|
+
}),
|
|
26
|
+
|
|
27
|
+
onResponse({ response }) {
|
|
28
|
+
if (response.status === 200) {
|
|
29
|
+
useCookie("accessToken", cookieConfig).value =
|
|
30
|
+
response._data.token;
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Expose to useNuxtApp().$api
|
|
39
|
+
return {
|
|
40
|
+
provide: {
|
|
41
|
+
api,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// import this after install `@mdi/font` package
|
|
2
|
+
import "@mdi/font/css/materialdesignicons.css";
|
|
3
|
+
|
|
4
|
+
import "vuetify/styles";
|
|
5
|
+
import { createVuetify } from "vuetify";
|
|
6
|
+
|
|
7
|
+
export default defineNuxtPlugin((app) => {
|
|
8
|
+
const vuetify = createVuetify({
|
|
9
|
+
defaults: {
|
|
10
|
+
VTextField: {
|
|
11
|
+
variant: "outlined",
|
|
12
|
+
density: "comfortable",
|
|
13
|
+
},
|
|
14
|
+
VAutocomplete: {
|
|
15
|
+
variant: "outlined",
|
|
16
|
+
density: "comfortable",
|
|
17
|
+
},
|
|
18
|
+
VSelect: {
|
|
19
|
+
variant: "outlined",
|
|
20
|
+
density: "comfortable",
|
|
21
|
+
},
|
|
22
|
+
VTextarea: {
|
|
23
|
+
variant: "outlined",
|
|
24
|
+
density: "comfortable",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
theme: {
|
|
28
|
+
defaultTheme: "iservice365",
|
|
29
|
+
themes: {
|
|
30
|
+
iservice365: {
|
|
31
|
+
dark: false,
|
|
32
|
+
colors: {
|
|
33
|
+
primary: "#042134",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
app.vueApp.use(vuetify);
|
|
41
|
+
});
|
package/tsconfig.json
ADDED