@nathapp/na-cli 1.0.8 → 1.0.10
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/templates/db-schema/.gitlab-ci.yml +139 -0
- package/dist/templates/db-schema/Makefile +885 -0
- package/dist/templates/k8s-deployment/.gitlab-ci.yml +158 -0
- package/dist/templates/k8s-deployment/Makefile +233 -0
- package/dist/templates/k8s-deployment/resources/charts/mysql/charts/mysql-install/script/Makefile +12 -0
- package/dist/templates/k8s-deployment/resources/charts/redis/charts/redis-install/script/Makefile +8 -0
- package/dist/templates/k8s-deployment/services/charts/hooks/charts/pre-delete-rsc/script/Makefile +56 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-cypress/Makefile +9 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/script/Makefile +14 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/_t-0100-readiness-liveness.ts +84 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/hub.ts +372 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-contact.ts +158 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-contract.ts +328 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-kyc.ts +304 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-onboard-app.ts +823 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-onboard-web.ts +493 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-profile.ts +277 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/individual-whitelist.ts +133 -0
- package/dist/templates/k8s-deployment/services/charts/tests/charts/e2e-test-js/tests/t-0200-start.ts +172 -0
- package/dist/templates/nestjs-api/.dockerignore +9 -0
- package/dist/templates/nestjs-api/.env +35 -0
- package/dist/templates/nestjs-api/.env.local +5 -29
- package/dist/templates/nestjs-api/.gitlab-ci.yml +180 -0
- package/dist/templates/nestjs-api/.nvmrc +1 -0
- package/dist/templates/nestjs-api/.prettierrc +4 -0
- package/dist/templates/nestjs-api/Makefile +95 -0
- package/dist/templates/nestjs-api/README.md +15 -0
- package/dist/templates/nestjs-api/nest-cli.json +10 -0
- package/dist/templates/nestjs-api/ormconfig.ts +16 -0
- package/dist/templates/nestjs-api/package.json +9 -9
- package/dist/templates/nestjs-api/src/app.controller.spec.ts +24 -0
- package/dist/templates/nestjs-api/src/app.controller.ts +27 -0
- package/dist/templates/nestjs-api/src/app.module.ts +33 -0
- package/dist/templates/nestjs-api/src/app.service.ts +27 -0
- package/dist/templates/nestjs-api/src/main.ts +31 -0
- package/dist/templates/nestjs-api/test/app.e2e-spec.ts +47 -0
- package/dist/templates/nestjs-api/tsconfig.build.json +5 -0
- package/dist/templates/nestjs-api/tsconfig.json +28 -0
- package/dist/templates/nestjs-api/tsconfig.spec.json +9 -0
- package/dist/templates/nestjs-library/.gitlab-ci.yml +134 -0
- package/dist/templates/nestjs-library/.nvmrc +1 -0
- package/dist/templates/nestjs-library/.prettierrc +6 -0
- package/dist/templates/nestjs-library/Makefile +60 -0
- package/dist/templates/nestjs-library/lib/index.ts +2 -0
- package/dist/templates/nestjs-library/test/app/controller/hello.controller.spec.ts +20 -0
- package/dist/templates/nestjs-library/test/app/controller/hello.controller.ts +7 -0
- package/dist/templates/nestjs-library/tsconfig.build.json +8 -0
- package/dist/templates/nestjs-library/tsconfig.json +21 -0
- package/dist/templates/nestjs-library/tsconfig.spec.json +9 -0
- package/dist/templates/ts-library/.dockerignore +2 -0
- package/dist/templates/ts-library/.eslintrc.js +24 -0
- package/dist/templates/ts-library/.gitlab-ci.yml +136 -0
- package/dist/templates/ts-library/.prettierrc +6 -0
- package/dist/templates/ts-library/Makefile +58 -0
- package/dist/templates/ts-library/index.ts +1 -0
- package/dist/templates/ts-library/lib/index.ts +1 -0
- package/dist/templates/ts-library/lib/samples/index.ts +5 -0
- package/dist/templates/ts-library/lib/samples/samples-function.ts +3 -0
- package/dist/templates/ts-library/test/sample.e2e-spec.ts +10 -0
- package/dist/templates/ts-library/tsconfig.build.json +4 -0
- package/dist/templates/ts-library/tsconfig.json +18 -0
- package/dist/templates/turbo-nestjs-vuexy/.dockerignore +2 -0
- package/dist/templates/turbo-nestjs-vuexy/.gitignore-rename +40 -0
- package/dist/templates/turbo-nestjs-vuexy/.npmrc-rename +0 -0
- package/dist/templates/turbo-nestjs-vuexy/Makefile +48 -0
- package/dist/templates/vuexy-portal/.dockerignore +2 -0
- package/dist/templates/vuexy-portal/.env +1 -0
- package/dist/templates/vuexy-portal/.gitlab-ci.yml +233 -0
- package/dist/templates/vuexy-portal/.npmrc-rename +2 -0
- package/dist/templates/vuexy-portal/.nvmrc +1 -0
- package/dist/templates/vuexy-portal/Makefile +55 -0
- package/dist/templates/vuexy-portal/src/@core/composable/createUrl.ts +20 -0
- package/dist/templates/vuexy-portal/src/@core/composable/useCookie.ts +43 -0
- package/dist/templates/vuexy-portal/src/@core/composable/useGenerateImageVariant.ts +25 -0
- package/dist/templates/vuexy-portal/src/@core/composable/useResponsiveSidebar.ts +29 -0
- package/dist/templates/vuexy-portal/src/@core/composable/useSkins.ts +42 -0
- package/dist/templates/vuexy-portal/src/@core/enums.ts +21 -0
- package/dist/templates/vuexy-portal/src/@core/index.ts +43 -0
- package/dist/templates/vuexy-portal/src/@core/initCore.ts +93 -0
- package/dist/templates/vuexy-portal/src/@core/libs/apex-chart/apexCharConfig.ts +701 -0
- package/dist/templates/vuexy-portal/src/@core/libs/chartjs/chartjsConfig.ts +372 -0
- package/dist/templates/vuexy-portal/src/@core/libs/chartjs/components/BarChart.ts +58 -0
- package/dist/templates/vuexy-portal/src/@core/libs/chartjs/components/BubbleChart.ts +58 -0
- package/dist/templates/vuexy-portal/src/@core/libs/chartjs/components/DoughnutChart.ts +58 -0
- package/dist/templates/vuexy-portal/src/@core/libs/chartjs/components/LineChart.ts +58 -0
- package/dist/templates/vuexy-portal/src/@core/libs/chartjs/components/PolarAreaChart.ts +58 -0
- package/dist/templates/vuexy-portal/src/@core/libs/chartjs/components/RadarChart.ts +58 -0
- package/dist/templates/vuexy-portal/src/@core/libs/chartjs/components/ScatterChart.ts +58 -0
- package/dist/templates/vuexy-portal/src/@core/stores/config.ts +80 -0
- package/dist/templates/vuexy-portal/src/@core/types.ts +49 -0
- package/dist/templates/vuexy-portal/src/@core/utils/formatters.ts +48 -0
- package/dist/templates/vuexy-portal/src/@core/utils/helpers.ts +32 -0
- package/dist/templates/vuexy-portal/src/@core/utils/plugins.ts +53 -0
- package/dist/templates/vuexy-portal/src/@core/utils/validators.ts +105 -0
- package/dist/templates/vuexy-portal/src/@core/utils/vuetify.ts +13 -0
- package/dist/templates/vuexy-portal/src/@custom/composables/toasts.ts +45 -0
- package/dist/templates/vuexy-portal/src/@custom/composables/validator.ts +160 -0
- package/dist/templates/vuexy-portal/src/@custom/enums/index.ts +0 -0
- package/dist/templates/vuexy-portal/src/@custom/types/common.ts +17 -0
- package/dist/templates/vuexy-portal/src/@custom/types/index.ts +0 -0
- package/dist/templates/vuexy-portal/src/@custom/types/pagination.ts +19 -0
- package/dist/templates/vuexy-portal/src/@custom/types/user.ts +5 -0
- package/dist/templates/vuexy-portal/src/@custom/utils/formatters.ts +83 -0
- package/dist/templates/vuexy-portal/src/@custom/utils/index.ts +0 -0
- package/dist/templates/vuexy-portal/src/@custom/utils/validators.ts +51 -0
- package/dist/templates/vuexy-portal/src/@layouts/components.ts +11 -0
- package/dist/templates/vuexy-portal/src/@layouts/config.ts +43 -0
- package/dist/templates/vuexy-portal/src/@layouts/enums.ts +27 -0
- package/dist/templates/vuexy-portal/src/@layouts/index.ts +49 -0
- package/dist/templates/vuexy-portal/src/@layouts/plugins/casl.ts +48 -0
- package/dist/templates/vuexy-portal/src/@layouts/stores/config.ts +115 -0
- package/dist/templates/vuexy-portal/src/@layouts/symbols.ts +1 -0
- package/dist/templates/vuexy-portal/src/@layouts/types.ts +126 -0
- package/dist/templates/vuexy-portal/src/@layouts/utils.ts +180 -0
- package/dist/templates/vuexy-portal/src/api/api.ts +1 -0
- package/dist/templates/vuexy-portal/src/api/commonApi.ts +25 -0
- package/dist/templates/vuexy-portal/src/api/index.ts +58 -0
- package/dist/templates/vuexy-portal/src/api/requestInterceptor.ts +21 -0
- package/dist/templates/vuexy-portal/src/api/responseInterceptor.ts +52 -0
- package/dist/templates/vuexy-portal/src/api/types.ts +14 -0
- package/dist/templates/vuexy-portal/src/api/useApi.ts +68 -0
- package/dist/templates/vuexy-portal/src/api/useFetchApi.ts +41 -0
- package/dist/templates/vuexy-portal/src/api/userApi.ts +11 -0
- package/dist/templates/vuexy-portal/src/composables/useApiFetch.ts +48 -0
- package/dist/templates/vuexy-portal/src/composables/useJwt.ts +108 -0
- package/dist/templates/vuexy-portal/src/main.ts +17 -0
- package/dist/templates/vuexy-portal/src/navigation/horizontal/index.ts +5 -0
- package/dist/templates/vuexy-portal/src/navigation/index.ts +7 -0
- package/dist/templates/vuexy-portal/src/navigation/vertical/index.ts +5 -0
- package/dist/templates/vuexy-portal/src/plugins/1.router/additional-routes.ts +23 -0
- package/dist/templates/vuexy-portal/src/plugins/1.router/guards.ts +50 -0
- package/dist/templates/vuexy-portal/src/plugins/1.router/index.ts +45 -0
- package/dist/templates/vuexy-portal/src/plugins/2.pinia.ts +8 -0
- package/dist/templates/vuexy-portal/src/plugins/casl/ability.ts +10 -0
- package/dist/templates/vuexy-portal/src/plugins/casl/composables/useAbility.ts +4 -0
- package/dist/templates/vuexy-portal/src/plugins/casl/index.ts +14 -0
- package/dist/templates/vuexy-portal/src/plugins/i18n/index.ts +29 -0
- package/dist/templates/vuexy-portal/src/plugins/iconify/build-icons.ts +299 -0
- package/dist/templates/vuexy-portal/src/plugins/iconify/index.ts +5 -0
- package/dist/templates/vuexy-portal/src/plugins/layouts.ts +13 -0
- package/dist/templates/vuexy-portal/src/plugins/toast/index.ts +9 -0
- package/dist/templates/vuexy-portal/src/plugins/vuetify/defaults.ts +192 -0
- package/dist/templates/vuexy-portal/src/plugins/vuetify/icons.ts +84 -0
- package/dist/templates/vuexy-portal/src/plugins/vuetify/index.ts +47 -0
- package/dist/templates/vuexy-portal/src/plugins/vuetify/theme.ts +155 -0
- package/dist/templates/vuexy-portal/src/plugins/webfontloader.ts +19 -0
- package/dist/templates/vuexy-portal/src/stores/auth.ts +22 -0
- package/dist/templates/vuexy-portal/src/stores/common.ts +41 -0
- package/dist/templates/vuexy-portal/src/stores/index.ts +0 -0
- package/dist/templates/vuexy-portal/src/utils/constants.ts +3 -0
- package/dist/templates/vuexy-portal/src/utils/paginationMeta.ts +10 -0
- package/dist/templates/vuexy-portal/themeConfig.ts +66 -0
- package/dist/templates/vuexy-portal/tsconfig.json +86 -0
- package/dist/templates/vuexy-portal/vite.config.ts +111 -0
- package/dist/utils/jwt-keys.js +26 -0
- package/dist/utils/jwt-keys.js.map +1 -0
- package/dist/utils/template.js +4 -1
- package/dist/utils/template.js.map +1 -1
- package/package.json +4 -1
- package/alias-script.sh +0 -30
- package/bunfig.toml +0 -3
- package/nax/config.json +0 -23
- package/nax/features/enhancements/prd.json +0 -61
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type { Router } from 'vue-router'
|
|
2
|
+
import { layoutConfig } from '@layouts/config'
|
|
3
|
+
import { AppContentLayoutNav } from '@layouts/enums'
|
|
4
|
+
import { useLayoutConfigStore } from '@layouts/stores/config'
|
|
5
|
+
import type { NavGroup, NavLink, NavLinkProps } from '@layouts/types'
|
|
6
|
+
|
|
7
|
+
export const openGroups = ref<string[]>([])
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Return nav link props to use
|
|
11
|
+
// @param {Object, String} item navigation routeName or route Object provided in navigation data
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export const getComputedNavLinkToProp = computed(() => (link: NavLink) => {
|
|
15
|
+
const props: NavLinkProps = {
|
|
16
|
+
target: link.target,
|
|
17
|
+
rel: link.rel,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// If route is string => it assumes string is route name => Create route object from route name
|
|
21
|
+
// If route is not string => It assumes it's route object => returns passed route object
|
|
22
|
+
if (link.to)
|
|
23
|
+
props.to = typeof link.to === 'string' ? { name: link.to } : link.to
|
|
24
|
+
else props.href = link.href
|
|
25
|
+
|
|
26
|
+
return props
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Return route name for navigation link
|
|
31
|
+
* If link is string then it will assume it is route-name
|
|
32
|
+
* IF link is object it will resolve the object and will return the link
|
|
33
|
+
// @param {Object, String} link navigation link object/string
|
|
34
|
+
*/
|
|
35
|
+
export const resolveNavLinkRouteName = (link: NavLink, router: Router) => {
|
|
36
|
+
if (!link.to)
|
|
37
|
+
return null
|
|
38
|
+
|
|
39
|
+
if (typeof link.to === 'string')
|
|
40
|
+
return link.to
|
|
41
|
+
|
|
42
|
+
return router.resolve(link.to).name
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Check if nav-link is active
|
|
47
|
+
* @param {object} link nav-link object
|
|
48
|
+
*/
|
|
49
|
+
export const isNavLinkActive = (link: NavLink, router: Router) => {
|
|
50
|
+
// Matched routes array of current route
|
|
51
|
+
const matchedRoutes = router.currentRoute.value.matched
|
|
52
|
+
|
|
53
|
+
// Check if provided route matches route's matched route
|
|
54
|
+
const resolveRoutedName = resolveNavLinkRouteName(link, router)
|
|
55
|
+
|
|
56
|
+
if (!resolveRoutedName)
|
|
57
|
+
return false
|
|
58
|
+
|
|
59
|
+
return matchedRoutes.some(route => {
|
|
60
|
+
return route.name === resolveRoutedName || route.meta.navActiveLink === resolveRoutedName
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if nav group is active
|
|
66
|
+
* @param {Array} children Group children
|
|
67
|
+
*/
|
|
68
|
+
export const isNavGroupActive = (children: (NavLink | NavGroup)[], router: Router): boolean =>
|
|
69
|
+
children.some(child => {
|
|
70
|
+
// If child have children => It's group => Go deeper(recursive)
|
|
71
|
+
if ('children' in child)
|
|
72
|
+
return isNavGroupActive(child.children, router)
|
|
73
|
+
|
|
74
|
+
// else it's link => Check for matched Route
|
|
75
|
+
return isNavLinkActive(child, router)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Change `dir` attribute based on direction
|
|
80
|
+
* @param dir 'ltr' | 'rtl'
|
|
81
|
+
*/
|
|
82
|
+
export const _setDirAttr = (dir: 'ltr' | 'rtl') => {
|
|
83
|
+
// Check if document exists for SSR
|
|
84
|
+
if (typeof document !== 'undefined')
|
|
85
|
+
document.documentElement.setAttribute('dir', dir)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Return dynamic i18n props based on i18n plugin is enabled or not
|
|
90
|
+
* @param key i18n translation key
|
|
91
|
+
* @param tag tag to wrap the translation with
|
|
92
|
+
*/
|
|
93
|
+
export const getDynamicI18nProps = (key: string, tag = 'span') => {
|
|
94
|
+
if (!layoutConfig.app.i18n.enable)
|
|
95
|
+
return {}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
keypath: key,
|
|
99
|
+
tag,
|
|
100
|
+
scope: 'global',
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const switchToVerticalNavOnLtOverlayNavBreakpoint = () => {
|
|
105
|
+
const configStore = useLayoutConfigStore()
|
|
106
|
+
|
|
107
|
+
/*
|
|
108
|
+
ℹ️ This is flag will hold nav type need to render when switching between lgAndUp from mdAndDown window width
|
|
109
|
+
|
|
110
|
+
Requirement: When we nav is set to `horizontal` and we hit the `mdAndDown` breakpoint nav type shall change to `vertical` nav
|
|
111
|
+
Now if we go back to `lgAndUp` breakpoint from `mdAndDown` how we will know which was previous nav type in large device?
|
|
112
|
+
|
|
113
|
+
Let's assign value of `appContentLayoutNav` as default value of lgAndUpNav. Why 🤔?
|
|
114
|
+
If template is viewed in lgAndUp
|
|
115
|
+
We will assign `appContentLayoutNav` value to `lgAndUpNav` because at this point both constant is same
|
|
116
|
+
Hence, for `lgAndUpNav` it will take value from theme config file
|
|
117
|
+
else
|
|
118
|
+
It will always show vertical nav and if user increase the window width it will fallback to `appContentLayoutNav` value
|
|
119
|
+
But `appContentLayoutNav` will be value set in theme config file
|
|
120
|
+
*/
|
|
121
|
+
const lgAndUpNav = ref(configStore.appContentLayoutNav)
|
|
122
|
+
|
|
123
|
+
/*
|
|
124
|
+
There might be case where we manually switch from vertical to horizontal nav and vice versa in `lgAndUp` screen
|
|
125
|
+
So when user comes back from `mdAndDown` to `lgAndUp` we can set updated nav type
|
|
126
|
+
For this we need to update the `lgAndUpNav` value if screen is `lgAndUp`
|
|
127
|
+
*/
|
|
128
|
+
watch(
|
|
129
|
+
() => configStore.appContentLayoutNav,
|
|
130
|
+
value => {
|
|
131
|
+
if (!configStore.isLessThanOverlayNavBreakpoint)
|
|
132
|
+
lgAndUpNav.value = value
|
|
133
|
+
},
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
/*
|
|
137
|
+
This is layout switching part
|
|
138
|
+
If it's `mdAndDown` => We will use vertical nav no matter what previous nav type was
|
|
139
|
+
Or if it's `lgAndUp` we need to switch back to `lgAndUp` nav type. For this we will tracker property `lgAndUpNav`
|
|
140
|
+
*/
|
|
141
|
+
watch(() => configStore.isLessThanOverlayNavBreakpoint, val => {
|
|
142
|
+
configStore.appContentLayoutNav = val ? AppContentLayoutNav.Vertical : lgAndUpNav.value
|
|
143
|
+
}, { immediate: true })
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Convert Hex color to rgb
|
|
148
|
+
* @param hex
|
|
149
|
+
*/
|
|
150
|
+
|
|
151
|
+
export const hexToRgb = (hex: string) => {
|
|
152
|
+
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
|
153
|
+
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i
|
|
154
|
+
|
|
155
|
+
hex = hex.replace(shorthandRegex, (m: string, r: string, g: string, b: string) => {
|
|
156
|
+
return r + r + g + g + b + b
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
|
160
|
+
|
|
161
|
+
return result ? `${Number.parseInt(result[1], 16)},${Number.parseInt(result[2], 16)},${Number.parseInt(result[3], 16)}` : null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
*RGBA color to Hex color with / without opacity
|
|
166
|
+
*/
|
|
167
|
+
export const rgbaToHex = (rgba: string, forceRemoveAlpha = false) => {
|
|
168
|
+
return (
|
|
169
|
+
`#${
|
|
170
|
+
rgba
|
|
171
|
+
.replace(/^rgba?\(|\s+|\)$/g, '') // Get's rgba / rgb string values
|
|
172
|
+
.split(',') // splits them at ","
|
|
173
|
+
.filter((string, index) => !forceRemoveAlpha || index !== 3)
|
|
174
|
+
.map(string => Number.parseFloat(string)) // Converts them to numbers
|
|
175
|
+
.map((number, index) => (index === 3 ? Math.round(number * 255) : number)) // Converts alpha to 255 number
|
|
176
|
+
.map(number => number.toString(16)) // Converts numbers to hex
|
|
177
|
+
.map(string => (string.length === 1 ? `0${string}` : string)) // Adds 0 when length of one number is 1
|
|
178
|
+
.join('')}`
|
|
179
|
+
)
|
|
180
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const $api = createPrivateAxios()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Country, State } from '@/@custom/types/common'
|
|
2
|
+
|
|
3
|
+
export const commonApi = {
|
|
4
|
+
fetchAvailableCountries: async (): Promise<Country[]> => {
|
|
5
|
+
const result = await $api.get('/config/country/supported')
|
|
6
|
+
|
|
7
|
+
return resolveResult<Country[]>(result)
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
fetchStateByCountryCode: async (countryCode: string): Promise<State[]> => {
|
|
11
|
+
const params = {
|
|
12
|
+
countryCode,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const result = await $api.get('/config/state', { params })
|
|
16
|
+
|
|
17
|
+
return resolveResult<State[]>(result)
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
fetchAvailableLanguages: async () => {
|
|
21
|
+
const result = await $api.get('/config/lang/supported')
|
|
22
|
+
|
|
23
|
+
return resolveResult(result)
|
|
24
|
+
},
|
|
25
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { AxiosResponse } from 'axios'
|
|
2
|
+
import axios from 'axios'
|
|
3
|
+
import type { ToastProps } from 'vue-toast-notification'
|
|
4
|
+
import { useToast } from 'vue-toast-notification'
|
|
5
|
+
import type { Result, TResult } from './types'
|
|
6
|
+
|
|
7
|
+
export const resolveResult: {
|
|
8
|
+
<T = any>(response: AxiosResponse): T
|
|
9
|
+
<T = any>(response: AxiosResponse, wrapResult: boolean): T | TResult<T>
|
|
10
|
+
} = <T = any>(response: AxiosResponse, wrapResult: boolean = true): Result<T> => {
|
|
11
|
+
const res = response.data
|
|
12
|
+
if (wrapResult)
|
|
13
|
+
return res.data as T
|
|
14
|
+
|
|
15
|
+
return res as TResult<T>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const useDisplayErrorMessage = (message: string, options?: ToastProps) => {
|
|
19
|
+
const $toast = useToast()
|
|
20
|
+
|
|
21
|
+
const opt = Object.assign({}, {
|
|
22
|
+
position: 'top-right',
|
|
23
|
+
duration: 3000,
|
|
24
|
+
dismissible: true,
|
|
25
|
+
pauseOnHover: true,
|
|
26
|
+
queue: true,
|
|
27
|
+
}, options)
|
|
28
|
+
|
|
29
|
+
$toast.error(message, opt)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const createAxios = (baseURL?: string) => {
|
|
33
|
+
const thisAxios = axios.create({
|
|
34
|
+
baseURL,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
thisAxios.interceptors.request.use(
|
|
38
|
+
config => requestInterceptor(config),
|
|
39
|
+
error => {
|
|
40
|
+
return Promise.reject(error)
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
thisAxios.interceptors.response.use(
|
|
45
|
+
(response: AxiosResponse) => successResponseInterceptor(response),
|
|
46
|
+
error => errorResponseInterceptor(error),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return thisAxios
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const createPrivateAxios = () => {
|
|
53
|
+
const baseURL = (window as any)?.configs?.VUE_APP_BASE_API
|
|
54
|
+
|| process.env.VUE_APP_BASE_API
|
|
55
|
+
|| import.meta.env.VITE_API_BASE_URL
|
|
56
|
+
|
|
57
|
+
return createAxios(baseURL)
|
|
58
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const resolveRequestConfigOrOption = (configOrOption: any) => {
|
|
2
|
+
const accessToken = useCookie('accessToken').value
|
|
3
|
+
const lang = useCookie('language').value || 'en_US'
|
|
4
|
+
|
|
5
|
+
configOrOption.headers = {
|
|
6
|
+
...configOrOption.headers,
|
|
7
|
+
lang,
|
|
8
|
+
}
|
|
9
|
+
if (accessToken) {
|
|
10
|
+
configOrOption.headers = {
|
|
11
|
+
...configOrOption.headers,
|
|
12
|
+
Authorization: `Bearer ${accessToken}`,
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return configOrOption
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const requestInterceptor = (configOrOption: any) => {
|
|
20
|
+
return resolveRequestConfigOrOption(configOrOption)
|
|
21
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* eslint-disable prefer-promise-reject-errors */
|
|
2
|
+
/* eslint-disable promise/no-promise-in-callback */
|
|
3
|
+
import type { AxiosResponse } from 'axios'
|
|
4
|
+
|
|
5
|
+
export const isOctetStreamResponse = (response: AxiosResponse) => {
|
|
6
|
+
return response.headers
|
|
7
|
+
&& response.headers['content-type'] === 'application/octet-stream;charset=utf-8'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const resolveSuccessResponse = (response: AxiosResponse) => {
|
|
11
|
+
const res = response.data
|
|
12
|
+
const errCode = res.ret
|
|
13
|
+
if (
|
|
14
|
+
isOctetStreamResponse(response)
|
|
15
|
+
)
|
|
16
|
+
return response
|
|
17
|
+
|
|
18
|
+
if (typeof errCode != 'undefined' && errCode !== 0)
|
|
19
|
+
return Promise.reject(res)
|
|
20
|
+
|
|
21
|
+
return response
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const resolveErrorResponse = async (error: any) => {
|
|
25
|
+
const authStore = useAuthStore()
|
|
26
|
+
const { response } = error
|
|
27
|
+
if (response) {
|
|
28
|
+
const data = response.data
|
|
29
|
+
if (response.status === 500 || response.status === 400) {
|
|
30
|
+
if (data.ret !== '0') {
|
|
31
|
+
useDisplayErrorMessage(data.message || data.msg)
|
|
32
|
+
|
|
33
|
+
return Promise.reject(data)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else if (response.status === 401 && response.config.url !== authStore.config.logoutEndpoint) {
|
|
37
|
+
await authStore.logout()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return data ? Promise.reject(data) : Promise.reject()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return Promise.reject()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const successResponseInterceptor = (response: AxiosResponse) => {
|
|
47
|
+
return resolveSuccessResponse(response)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const errorResponseInterceptor = (error: any) => {
|
|
51
|
+
return resolveErrorResponse(error)
|
|
52
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AxiosRequestConfig } from 'axios'
|
|
2
|
+
|
|
3
|
+
export interface TResult<T = any> {
|
|
4
|
+
ret: number
|
|
5
|
+
|
|
6
|
+
data: T
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type Result<T = any> = T | TResult<T>
|
|
10
|
+
|
|
11
|
+
export interface RequestConfig<D = any> extends AxiosRequestConfig<D> {
|
|
12
|
+
wrapResult?: boolean
|
|
13
|
+
immediate?: boolean
|
|
14
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ref } from 'vue'
|
|
2
|
+
import type { RequestConfig, Result } from './types'
|
|
3
|
+
|
|
4
|
+
const defaultRequestConfig: RequestConfig = {
|
|
5
|
+
wrapResult: true,
|
|
6
|
+
immediate: false,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const useAxios = () => {
|
|
10
|
+
return createPrivateAxios()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const useApi = <T = Result>(config: RequestConfig) => {
|
|
14
|
+
const axios = useAxios()
|
|
15
|
+
const error = ref(null)
|
|
16
|
+
const data = ref<T>()
|
|
17
|
+
const loading = ref(false)
|
|
18
|
+
const configIns = ref({ ...defaultRequestConfig, ...config })
|
|
19
|
+
|
|
20
|
+
const { wrapResult, immediate } = configIns.value
|
|
21
|
+
|
|
22
|
+
const execute = async (): Promise<T> => {
|
|
23
|
+
data.value = undefined
|
|
24
|
+
error.value = null
|
|
25
|
+
loading.value = true
|
|
26
|
+
try {
|
|
27
|
+
const response = await axios(configIns.value)
|
|
28
|
+
const res = response.data
|
|
29
|
+
let result
|
|
30
|
+
if (wrapResult)
|
|
31
|
+
result = res.data
|
|
32
|
+
else
|
|
33
|
+
result = res
|
|
34
|
+
|
|
35
|
+
data.value = result
|
|
36
|
+
|
|
37
|
+
return result
|
|
38
|
+
}
|
|
39
|
+
catch (err: any) {
|
|
40
|
+
error.value = err
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
loading.value = false
|
|
44
|
+
}
|
|
45
|
+
if (wrapResult) {
|
|
46
|
+
return {} as any
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
return {
|
|
50
|
+
ret: -1,
|
|
51
|
+
data: null,
|
|
52
|
+
} as any
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (immediate) {
|
|
57
|
+
watchEffect(() => {
|
|
58
|
+
execute()
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
execute,
|
|
64
|
+
error,
|
|
65
|
+
data,
|
|
66
|
+
loading,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createFetch } from '@vueuse/core'
|
|
2
|
+
import { destr } from 'destr'
|
|
3
|
+
|
|
4
|
+
export const useFetchApi = createFetch({
|
|
5
|
+
baseUrl: (window as any)?.configs?.VUE_APP_BASE_API
|
|
6
|
+
|| process.env.VUE_APP_BASE_API
|
|
7
|
+
|| import.meta.env.VITE_API_BASE_URL,
|
|
8
|
+
fetchOptions: {
|
|
9
|
+
headers: {
|
|
10
|
+
Accept: 'application/json',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
options: {
|
|
14
|
+
refetch: true,
|
|
15
|
+
async beforeFetch({ options }) {
|
|
16
|
+
options = resolveRequestConfigOrOption(options)
|
|
17
|
+
|
|
18
|
+
return { options }
|
|
19
|
+
},
|
|
20
|
+
afterFetch(ctx) {
|
|
21
|
+
const { data, response } = ctx
|
|
22
|
+
|
|
23
|
+
// Parse data if it's JSON
|
|
24
|
+
|
|
25
|
+
let parsedData = null
|
|
26
|
+
try {
|
|
27
|
+
parsedData = destr(data)
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error(error)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return { data: parsedData, response }
|
|
34
|
+
},
|
|
35
|
+
onFetchError(ctx) {
|
|
36
|
+
const { data, response, error } = ctx
|
|
37
|
+
|
|
38
|
+
return { data, response, error }
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MaybeRefOrGetter } from 'vue'
|
|
2
|
+
import type { TResult } from './types'
|
|
3
|
+
import type { ChangePasswordForm } from '@/@custom/types/user'
|
|
4
|
+
|
|
5
|
+
export const userApi = {
|
|
6
|
+
changePassword: async (form: MaybeRefOrGetter<ChangePasswordForm>) => {
|
|
7
|
+
const result = await $api.post('/auth/change-password', toValue(form))
|
|
8
|
+
|
|
9
|
+
return resolveResult(result, false) as TResult<any>
|
|
10
|
+
},
|
|
11
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createFetch } from '@vueuse/core';
|
|
2
|
+
import { destr } from 'destr';
|
|
3
|
+
|
|
4
|
+
export const useApiFetch = createFetch({
|
|
5
|
+
baseUrl: (window as any)?.configs?.VUE_APP_BASE_API ||
|
|
6
|
+
process.env.VUE_APP_BASE_API ||
|
|
7
|
+
import.meta.env.VITE_API_BASE_URL,
|
|
8
|
+
fetchOptions: {
|
|
9
|
+
headers: {
|
|
10
|
+
Accept: 'application/json',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
options: {
|
|
14
|
+
refetch: true,
|
|
15
|
+
async beforeFetch({ options }) {
|
|
16
|
+
const accessToken = useCookie('accessToken').value
|
|
17
|
+
const lang = useCookie('language').value || 'en_US';
|
|
18
|
+
|
|
19
|
+
options.headers = {
|
|
20
|
+
...options.headers,
|
|
21
|
+
lang,
|
|
22
|
+
}
|
|
23
|
+
if (accessToken) {
|
|
24
|
+
options.headers = {
|
|
25
|
+
...options.headers,
|
|
26
|
+
Authorization: `Bearer ${accessToken}`,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { options }
|
|
31
|
+
},
|
|
32
|
+
afterFetch(ctx) {
|
|
33
|
+
const { data, response } = ctx
|
|
34
|
+
|
|
35
|
+
// Parse data if it's JSON
|
|
36
|
+
|
|
37
|
+
let parsedData: any = null
|
|
38
|
+
try {
|
|
39
|
+
parsedData = destr(data)
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error(error)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { data: parsedData, response }
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
})
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { AxiosInstance } from 'axios'
|
|
2
|
+
import axios from 'axios'
|
|
3
|
+
import { md5 } from 'js-md5'
|
|
4
|
+
|
|
5
|
+
export interface JwtConfig {
|
|
6
|
+
loginEndpoint: string
|
|
7
|
+
|
|
8
|
+
logoutEndpoint?: string
|
|
9
|
+
|
|
10
|
+
refreshEndpoint?: string
|
|
11
|
+
|
|
12
|
+
tokenType: string
|
|
13
|
+
|
|
14
|
+
accessTokenKeyName: string
|
|
15
|
+
|
|
16
|
+
refreshTokenKeyName: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const defaultJwtConfig: JwtConfig = {
|
|
20
|
+
loginEndpoint: '/auth/login',
|
|
21
|
+
|
|
22
|
+
refreshEndpoint: '/auth/refresh-token',
|
|
23
|
+
|
|
24
|
+
logoutEndpoint: '/auth/logout',
|
|
25
|
+
|
|
26
|
+
tokenType: 'Bearer',
|
|
27
|
+
|
|
28
|
+
accessTokenKeyName: 'accessToken',
|
|
29
|
+
|
|
30
|
+
refreshTokenKeyName: 'refreshToken',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const loginInternal = async (data: any, config: JwtConfig, axiosIns: AxiosInstance) => {
|
|
34
|
+
const headers = {
|
|
35
|
+
// gsign: data.gsign,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
delete data.gsign
|
|
39
|
+
data.password = md5(data.password)
|
|
40
|
+
|
|
41
|
+
return axiosIns.post(config.loginEndpoint, data, { headers })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const useJwt = (jwtOverrideConfig?: JwtConfig, axiosIns?: AxiosInstance) => {
|
|
45
|
+
const config = Object.assign({}, defaultJwtConfig, jwtOverrideConfig)
|
|
46
|
+
const innerAxios = axiosIns || axios
|
|
47
|
+
const userData = useCookie<any>('userData')
|
|
48
|
+
const ability = useAbility()
|
|
49
|
+
|
|
50
|
+
const getToken = () => {
|
|
51
|
+
return useCookie(config.accessTokenKeyName).value
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const getRefreshToken = () => {
|
|
55
|
+
return useCookie(config.refreshTokenKeyName).value
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const login = (data: any) => {
|
|
59
|
+
return loginInternal(data, config, innerAxios)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const logout = async (callback?: () => void) => {
|
|
63
|
+
if (config.logoutEndpoint) {
|
|
64
|
+
try {
|
|
65
|
+
await innerAxios.post(config.logoutEndpoint)
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.error('logout error', err)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Remove "accessToken" from cookie
|
|
73
|
+
useCookie('accessToken').value = null
|
|
74
|
+
|
|
75
|
+
// Remove "userData" from cookie
|
|
76
|
+
userData.value = null
|
|
77
|
+
useCookie('userData').value = null
|
|
78
|
+
|
|
79
|
+
// ℹ️ We had to remove abilities in then block because if we don't nav menu items mutation is visible while redirecting user to login page
|
|
80
|
+
// Remove "userAbilities" from cookie
|
|
81
|
+
useCookie('userAbilityRules').value = null
|
|
82
|
+
|
|
83
|
+
// Reset ability to initial ability
|
|
84
|
+
ability.update([])
|
|
85
|
+
|
|
86
|
+
typeof callback === 'function' && callback()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const refreshToken = () => {
|
|
90
|
+
const { refreshEndpoint } = config
|
|
91
|
+
|
|
92
|
+
if (!refreshEndpoint)
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
return innerAxios.post(refreshEndpoint, {
|
|
96
|
+
refreshToken: getRefreshToken(),
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
config,
|
|
102
|
+
getToken,
|
|
103
|
+
getRefreshToken,
|
|
104
|
+
login,
|
|
105
|
+
logout,
|
|
106
|
+
refreshToken,
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
|
|
3
|
+
import App from '@/App.vue'
|
|
4
|
+
import { registerPlugins } from '@core/utils/plugins'
|
|
5
|
+
|
|
6
|
+
// Styles
|
|
7
|
+
import '@core/scss/template/index.scss'
|
|
8
|
+
import '@styles/styles.scss'
|
|
9
|
+
|
|
10
|
+
// Create vue app
|
|
11
|
+
const app = createApp(App)
|
|
12
|
+
|
|
13
|
+
// Register plugins
|
|
14
|
+
registerPlugins(app)
|
|
15
|
+
|
|
16
|
+
// Mount vue app
|
|
17
|
+
app.mount('#app')
|