@finema/finework-layer 0.2.77 → 0.2.79

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.
Files changed (41) hide show
  1. package/.husky/pre-commit +1 -1
  2. package/.playground/app/assets/css/main.css +6 -6
  3. package/.playground/app/pages/layout-admin/[id]/index.vue +145 -145
  4. package/.playground/app/pages/layout-admin/test/[id]/index.vue +286 -286
  5. package/.playground/app/pages/layout-admin.vue +283 -285
  6. package/.playground/app/pages/layout-user.vue +284 -284
  7. package/.playground/app/pages/submenu/layout-admin.vue +210 -210
  8. package/.vscode/settings.json +5 -1
  9. package/CHANGELOG.md +382 -374
  10. package/app/app.config.ts +144 -144
  11. package/app/app.vue +10 -10
  12. package/app/assets/css/main.css +77 -77
  13. package/app/components/Button/ActionIcon.vue +29 -29
  14. package/app/components/Button/Back.vue +22 -22
  15. package/app/components/Format/Currency.vue +17 -17
  16. package/app/components/Format/Date.vue +24 -24
  17. package/app/components/Format/DateTime.vue +24 -24
  18. package/app/components/Format/Number.vue +17 -17
  19. package/app/components/Format/Percent.vue +38 -38
  20. package/app/components/Format/TimeFromNow.vue +38 -38
  21. package/app/components/InfoItemList.vue +196 -196
  22. package/app/components/Layout/Admin/Sidebar.vue +343 -329
  23. package/app/components/Layout/Admin/index.vue +240 -224
  24. package/app/components/Layout/Apps.vue +45 -45
  25. package/app/components/Layout/User/index.vue +102 -102
  26. package/app/components/Notifications/index.vue +162 -162
  27. package/app/components/StatusBox.vue +56 -56
  28. package/app/composables/useAuth.ts +207 -207
  29. package/app/composables/useNotification.ts +76 -76
  30. package/app/composables/useRequestOptions.ts +86 -86
  31. package/app/constants/routes.ts +86 -86
  32. package/app/error.vue +218 -218
  33. package/app/middleware/auth.ts +45 -45
  34. package/app/middleware/common.ts +12 -12
  35. package/app/middleware/guest.ts +7 -7
  36. package/app/middleware/permissions.ts +29 -29
  37. package/bun.lock +2758 -2758
  38. package/eslint.config.js +206 -2
  39. package/index.d.ts +16 -16
  40. package/nuxt.config.ts +41 -41
  41. package/package.json +38 -38
@@ -1,207 +1,207 @@
1
- export enum Permission {
2
- USER = 'USER',
3
- ADMIN = 'ADMIN',
4
- SUPER = 'SUPER',
5
- NONE = 'NONE',
6
- }
7
-
8
- export const PERMISSION_LABEL = {
9
- [Permission.ADMIN]: 'Admin',
10
- [Permission.USER]: 'User',
11
- [Permission.SUPER]: 'Settings',
12
- [Permission.NONE]: 'No Access',
13
- }
14
-
15
- export interface ITeam {
16
- id: string
17
- name: string
18
- code: string
19
- color: string
20
- description?: string
21
- working_start_at: string
22
- working_end_at: string
23
- users: IUser[] | null
24
- created_at: string
25
- updated_at: string
26
- }
27
-
28
- export interface IUser {
29
- id: string
30
- email: string
31
- full_name: string
32
- display_name: string
33
- position: string
34
- team: ITeam
35
- team_code: string
36
- avatar_url: string
37
- company: string
38
- sig: string
39
- access_level: IUserAccessLevel
40
- is_active: boolean
41
- joined_date: string
42
- slack_id: string
43
- created_at: string
44
- updated_at: string
45
- }
46
-
47
- export enum UserModule {
48
- CHECKIN = 'clockin',
49
- PMO = 'pmo',
50
- TIMESHEET = 'timesheet',
51
- SETTING = 'setting',
52
- }
53
-
54
- export interface IUserAccessLevel {
55
- used_id: string
56
- pmo: Permission.USER | Permission.ADMIN | Permission.SUPER
57
- clockin: Permission.USER | Permission.ADMIN
58
- timesheet: Permission.USER | Permission.ADMIN
59
- setting: Permission.USER | Permission.SUPER
60
- }
61
-
62
- export const useAuth = () => {
63
- const {
64
- auth,
65
- } = useRequestOptions()
66
-
67
- const token = useCookie('token', {
68
- path: '/',
69
- maxAge: 60 * 60 * 24 * 365,
70
- })
71
-
72
- const isAuthenticated = computed(() => !!token.value)
73
- const me = defineStore('auth.me', () => {
74
- const value = ref<IUser | null>(null)
75
- const timestamp = ref<number | null>(null)
76
-
77
- const set = (user: IUser | null) => {
78
- value.value = user
79
- }
80
-
81
- const setTimestamp = (t: number | null) => {
82
- timestamp.value = t
83
- }
84
-
85
- const isShouldFetch = () => {
86
- if (!value.value || !timestamp.value) return true
87
-
88
- // expire after 1 min - fetch if timestamp is older than 1 minute ago
89
- return Date.now() - timestamp.value > 1000 * 60 * 1
90
- }
91
-
92
- return {
93
- value,
94
- set,
95
- timestamp,
96
- setTimestamp,
97
- isShouldFetch,
98
- }
99
- })()
100
-
101
- const fetchMe = (() => {
102
- return useObjectLoader<IUser>({
103
- method: 'GET',
104
- url: '/me',
105
- getRequestOptions: auth,
106
- })
107
- })()
108
-
109
- const updateMe = (() => {
110
- return useObjectLoader<IUser>({
111
- method: 'PUT',
112
- url: '/me',
113
- getRequestOptions: auth,
114
- })
115
- })()
116
-
117
- const loginSlack = async () => {
118
- const config = useRuntimeConfig()
119
-
120
- window.location.href = config.public.baseAPI + '/auth/slack-login'
121
- }
122
-
123
- const loginMs = async () => {
124
- const config = useRuntimeConfig()
125
-
126
- window.location.href = config.public.baseAPI + '/auth/ms-login'
127
- }
128
-
129
- useWatchTrue(() => fetchMe.status.value.isSuccess, () => {
130
- me.setTimestamp(Date.now())
131
- me.set(fetchMe.data.value)
132
- })
133
-
134
- useWatchTrue(() => fetchMe.status.value.isError, () => {
135
- token.value = undefined
136
- me.setTimestamp(null)
137
- me.set(null)
138
- })
139
-
140
- const hasPermission = (module: UserModule, ...permission: Permission[]) => {
141
- if (!me.value?.access_level) {
142
- return false
143
- }
144
-
145
- return permission.includes(me.value.access_level[module])
146
- }
147
-
148
- const isSuperAdmin = computed(() => {
149
- return me.value?.access_level?.setting === Permission.SUPER
150
- })
151
-
152
- const menusNavbar = computed(() => [
153
- {
154
- label: 'Clock-In',
155
- icon: '/admin/clock-in-logo.png',
156
- to: routes.clockin.home.to,
157
- },
158
- {
159
- label: 'Timesheet',
160
- icon: '/admin/timesheet-logo.png',
161
- to: routes.timesheet.home.to,
162
- },
163
- ...(hasPermission(UserModule.PMO, Permission.ADMIN, Permission.USER, Permission.SUPER)
164
- ? [{
165
- label: 'PMO',
166
- icon: '/admin/pmo-logo.png',
167
- to: routes.pmo.project.projects.to,
168
- }]
169
- : []),
170
- ...(hasPermission(UserModule.CHECKIN, Permission.ADMIN)
171
- ? [{
172
- label: 'Clock-In Admin',
173
- icon: '/admin/clock-in-admin-logo.png',
174
- to: routes.adminClockin.checkinDashboard.to,
175
- }]
176
- : []),
177
- ...(hasPermission(UserModule.TIMESHEET, Permission.ADMIN)
178
- ? [{
179
- label: 'Timesheet Admin',
180
- icon: '/admin/timesheet-admin-logo.png',
181
- to: routes.adminTimesheet.summaryReport.to,
182
- }]
183
- : []),
184
-
185
- ...(hasPermission(UserModule.SETTING, Permission.SUPER)
186
- ? [{
187
- label: 'Settings',
188
- icon: '/admin/super-admin-logo.png',
189
- to: routes.admin.users.to,
190
- }]
191
- : []),
192
- ])
193
-
194
- return {
195
- token,
196
- loginSlack,
197
- loginMs,
198
- isAuthenticated,
199
- me,
200
- fetchMe,
201
- updateMe,
202
- hasPermission,
203
- isSuperAdmin,
204
- menusNavbar,
205
-
206
- }
207
- }
1
+ export enum Permission {
2
+ USER = 'USER',
3
+ ADMIN = 'ADMIN',
4
+ SUPER = 'SUPER',
5
+ NONE = 'NONE',
6
+ }
7
+
8
+ export const PERMISSION_LABEL = {
9
+ [Permission.ADMIN]: 'Admin',
10
+ [Permission.USER]: 'User',
11
+ [Permission.SUPER]: 'Settings',
12
+ [Permission.NONE]: 'No Access',
13
+ }
14
+
15
+ export interface ITeam {
16
+ id: string
17
+ name: string
18
+ code: string
19
+ color: string
20
+ description?: string
21
+ working_start_at: string
22
+ working_end_at: string
23
+ users: IUser[] | null
24
+ created_at: string
25
+ updated_at: string
26
+ }
27
+
28
+ export interface IUser {
29
+ id: string
30
+ email: string
31
+ full_name: string
32
+ display_name: string
33
+ position: string
34
+ team: ITeam
35
+ team_code: string
36
+ avatar_url: string
37
+ company: string
38
+ sig: string
39
+ access_level: IUserAccessLevel
40
+ is_active: boolean
41
+ joined_date: string
42
+ slack_id: string
43
+ created_at: string
44
+ updated_at: string
45
+ }
46
+
47
+ export enum UserModule {
48
+ CHECKIN = 'clockin',
49
+ PMO = 'pmo',
50
+ TIMESHEET = 'timesheet',
51
+ SETTING = 'setting',
52
+ }
53
+
54
+ export interface IUserAccessLevel {
55
+ used_id: string
56
+ pmo: Permission.USER | Permission.ADMIN | Permission.SUPER
57
+ clockin: Permission.USER | Permission.ADMIN
58
+ timesheet: Permission.USER | Permission.ADMIN
59
+ setting: Permission.USER | Permission.SUPER
60
+ }
61
+
62
+ export const useAuth = () => {
63
+ const {
64
+ auth,
65
+ } = useRequestOptions()
66
+
67
+ const token = useCookie('token', {
68
+ path: '/',
69
+ maxAge: 60 * 60 * 24 * 365,
70
+ })
71
+
72
+ const isAuthenticated = computed(() => !!token.value)
73
+ const me = defineStore('auth.me', () => {
74
+ const value = ref<IUser | null>(null)
75
+ const timestamp = ref<number | null>(null)
76
+
77
+ const set = (user: IUser | null) => {
78
+ value.value = user
79
+ }
80
+
81
+ const setTimestamp = (t: number | null) => {
82
+ timestamp.value = t
83
+ }
84
+
85
+ const isShouldFetch = () => {
86
+ if (!value.value || !timestamp.value) return true
87
+
88
+ // expire after 1 min - fetch if timestamp is older than 1 minute ago
89
+ return Date.now() - timestamp.value > 1000 * 60 * 1
90
+ }
91
+
92
+ return {
93
+ value,
94
+ set,
95
+ timestamp,
96
+ setTimestamp,
97
+ isShouldFetch,
98
+ }
99
+ })()
100
+
101
+ const fetchMe = (() => {
102
+ return useObjectLoader<IUser>({
103
+ method: 'GET',
104
+ url: '/me',
105
+ getRequestOptions: auth,
106
+ })
107
+ })()
108
+
109
+ const updateMe = (() => {
110
+ return useObjectLoader<IUser>({
111
+ method: 'PUT',
112
+ url: '/me',
113
+ getRequestOptions: auth,
114
+ })
115
+ })()
116
+
117
+ const loginSlack = async () => {
118
+ const config = useRuntimeConfig()
119
+
120
+ window.location.href = config.public.baseAPI + '/auth/slack-login'
121
+ }
122
+
123
+ const loginMs = async () => {
124
+ const config = useRuntimeConfig()
125
+
126
+ window.location.href = config.public.baseAPI + '/auth/ms-login'
127
+ }
128
+
129
+ useWatchTrue(() => fetchMe.status.value.isSuccess, () => {
130
+ me.setTimestamp(Date.now())
131
+ me.set(fetchMe.data.value)
132
+ })
133
+
134
+ useWatchTrue(() => fetchMe.status.value.isError, () => {
135
+ token.value = undefined
136
+ me.setTimestamp(null)
137
+ me.set(null)
138
+ })
139
+
140
+ const hasPermission = (module: UserModule, ...permission: Permission[]) => {
141
+ if (!me.value?.access_level) {
142
+ return false
143
+ }
144
+
145
+ return permission.includes(me.value.access_level[module])
146
+ }
147
+
148
+ const isSuperAdmin = computed(() => {
149
+ return me.value?.access_level?.setting === Permission.SUPER
150
+ })
151
+
152
+ const menusNavbar = computed(() => [
153
+ {
154
+ label: 'Clock-In',
155
+ icon: '/admin/clock-in-logo.png',
156
+ to: routes.clockin.home.to,
157
+ },
158
+ {
159
+ label: 'Timesheet',
160
+ icon: '/admin/timesheet-logo.png',
161
+ to: routes.timesheet.home.to,
162
+ },
163
+ ...(hasPermission(UserModule.PMO, Permission.ADMIN, Permission.USER, Permission.SUPER)
164
+ ? [{
165
+ label: 'PMO',
166
+ icon: '/admin/pmo-logo.png',
167
+ to: routes.pmo.project.projects.to,
168
+ }]
169
+ : []),
170
+ ...(hasPermission(UserModule.CHECKIN, Permission.ADMIN)
171
+ ? [{
172
+ label: 'Clock-In Admin',
173
+ icon: '/admin/clock-in-admin-logo.png',
174
+ to: routes.adminClockin.checkinDashboard.to,
175
+ }]
176
+ : []),
177
+ ...(hasPermission(UserModule.TIMESHEET, Permission.ADMIN)
178
+ ? [{
179
+ label: 'Timesheet Admin',
180
+ icon: '/admin/timesheet-admin-logo.png',
181
+ to: routes.adminTimesheet.summaryReport.to,
182
+ }]
183
+ : []),
184
+
185
+ ...(hasPermission(UserModule.SETTING, Permission.SUPER)
186
+ ? [{
187
+ label: 'Settings',
188
+ icon: '/admin/super-admin-logo.png',
189
+ to: routes.admin.users.to,
190
+ }]
191
+ : []),
192
+ ])
193
+
194
+ return {
195
+ token,
196
+ loginSlack,
197
+ loginMs,
198
+ isAuthenticated,
199
+ me,
200
+ fetchMe,
201
+ updateMe,
202
+ hasPermission,
203
+ isSuperAdmin,
204
+ menusNavbar,
205
+
206
+ }
207
+ }
@@ -1,76 +1,76 @@
1
- export const NotificationType = {
2
- INFO: 'INFO',
3
- SUCCESS: 'SUCCESS',
4
- WARNING: 'WARNING',
5
- ERROR: 'ERROR',
6
- MENTION: 'MENTION',
7
- COMMENT: 'COMMENT',
8
- ASSIGNMENT: 'ASSIGNMENT',
9
- DEADLINE: 'DEADLINE',
10
- APPROVAL: 'APPROVAL',
11
- REMINDER: 'REMINDER',
12
- SYSTEM: 'SYSTEM',
13
- }
14
-
15
- export const NotificationPMOActionType = {
16
- PROJECT_CREATE: 'PROJECT_CREATE',
17
- PROJECT_STATUS_CHANGED: 'PROJECT_STATUS_CHANGED',
18
- PROJECT_OWNER_CHANGED: 'PROJECT_OWNER_CHANGED',
19
- PROJECT_UPDATE: 'PROJECT_UPDATE',
20
-
21
- COLLABORATOR_ADD: 'COLLABORATOR_ADD',
22
- COLLABORATOR_UPDATE: 'COLLABORATOR_UPDATE',
23
- COLLABORATOR_REMOVE: 'COLLABORATOR_REMOVE',
24
- }
25
-
26
- export interface INotificationItem {
27
- id: string
28
- created_at: string
29
- updated_at: string
30
- user_id: string
31
- type: typeof NotificationType[keyof typeof NotificationType]
32
- title: string
33
- message: string
34
- data?: Record<string, any>
35
- source_type?: 'PMO_PROJECT' | string
36
- source_id?: string
37
- actor_id?: string
38
- action_type?: typeof NotificationPMOActionType[keyof typeof NotificationPMOActionType] & string
39
- is_read: boolean
40
- read_at: string
41
- channels: string[]
42
- sent_at: string
43
- user: IUser
44
- actor?: IUser
45
- }
46
-
47
- export const useNotificationLoader = defineStore('notification', () => {
48
- const options = useRequestOptions()
49
-
50
- return usePageLoader<INotificationItem>({
51
- baseURL: '/notifications?limit=30',
52
- getBaseRequestOptions: options.auth,
53
- })
54
- })
55
-
56
- export const useNotificationUnreadCount = defineStore('notification-unread-count', () => {
57
- const options = useRequestOptions()
58
-
59
- return useObjectLoader<{
60
- count: number
61
- }>({
62
- url: '/notifications/unread-count',
63
- method: 'get',
64
- getRequestOptions: options.auth,
65
- })
66
- })
67
-
68
- export const useNotificationMarkAllRead = () => {
69
- const options = useRequestOptions()
70
-
71
- return useObjectLoader({
72
- url: '/notifications/mark-all-read',
73
- method: 'post',
74
- getRequestOptions: options.auth,
75
- })
76
- }
1
+ export const NotificationType = {
2
+ INFO: 'INFO',
3
+ SUCCESS: 'SUCCESS',
4
+ WARNING: 'WARNING',
5
+ ERROR: 'ERROR',
6
+ MENTION: 'MENTION',
7
+ COMMENT: 'COMMENT',
8
+ ASSIGNMENT: 'ASSIGNMENT',
9
+ DEADLINE: 'DEADLINE',
10
+ APPROVAL: 'APPROVAL',
11
+ REMINDER: 'REMINDER',
12
+ SYSTEM: 'SYSTEM',
13
+ }
14
+
15
+ export const NotificationPMOActionType = {
16
+ PROJECT_CREATE: 'PROJECT_CREATE',
17
+ PROJECT_STATUS_CHANGED: 'PROJECT_STATUS_CHANGED',
18
+ PROJECT_OWNER_CHANGED: 'PROJECT_OWNER_CHANGED',
19
+ PROJECT_UPDATE: 'PROJECT_UPDATE',
20
+
21
+ COLLABORATOR_ADD: 'COLLABORATOR_ADD',
22
+ COLLABORATOR_UPDATE: 'COLLABORATOR_UPDATE',
23
+ COLLABORATOR_REMOVE: 'COLLABORATOR_REMOVE',
24
+ }
25
+
26
+ export interface INotificationItem {
27
+ id: string
28
+ created_at: string
29
+ updated_at: string
30
+ user_id: string
31
+ type: typeof NotificationType[keyof typeof NotificationType]
32
+ title: string
33
+ message: string
34
+ data?: Record<string, any>
35
+ source_type?: 'PMO_PROJECT' | string
36
+ source_id?: string
37
+ actor_id?: string
38
+ action_type?: typeof NotificationPMOActionType[keyof typeof NotificationPMOActionType] & string
39
+ is_read: boolean
40
+ read_at: string
41
+ channels: string[]
42
+ sent_at: string
43
+ user: IUser
44
+ actor?: IUser
45
+ }
46
+
47
+ export const useNotificationLoader = defineStore('notification', () => {
48
+ const options = useRequestOptions()
49
+
50
+ return usePageLoader<INotificationItem>({
51
+ baseURL: '/notifications?limit=30',
52
+ getBaseRequestOptions: options.auth,
53
+ })
54
+ })
55
+
56
+ export const useNotificationUnreadCount = defineStore('notification-unread-count', () => {
57
+ const options = useRequestOptions()
58
+
59
+ return useObjectLoader<{
60
+ count: number
61
+ }>({
62
+ url: '/notifications/unread-count',
63
+ method: 'get',
64
+ getRequestOptions: options.auth,
65
+ })
66
+ })
67
+
68
+ export const useNotificationMarkAllRead = () => {
69
+ const options = useRequestOptions()
70
+
71
+ return useObjectLoader({
72
+ url: '/notifications/mark-all-read',
73
+ method: 'post',
74
+ getRequestOptions: options.auth,
75
+ })
76
+ }