@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.
Files changed (39) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.editorconfig +12 -0
  4. package/.github/workflows/main.yml +17 -0
  5. package/.github/workflows/publish.yml +39 -0
  6. package/.nuxtrc +1 -0
  7. package/.playground/app.vue +36 -0
  8. package/.playground/eslint.config.mjs +6 -0
  9. package/.playground/nuxt.config.ts +22 -0
  10. package/CHANGELOG.md +8 -0
  11. package/README.md +73 -0
  12. package/app.vue +3 -0
  13. package/components/BtnUploadFile.vue +139 -0
  14. package/components/Input/Date.vue +177 -0
  15. package/components/Input/Password.vue +22 -0
  16. package/components/InputLabel.vue +18 -0
  17. package/components/Layout/Header.vue +248 -0
  18. package/components/Layout/NavigationDrawer.vue +24 -0
  19. package/components/ListItem.vue +35 -0
  20. package/components/LocalPagination.vue +31 -0
  21. package/components/NavigationItem.vue +59 -0
  22. package/components/PlaceholderComponent.vue +34 -0
  23. package/components/Snackbar.vue +23 -0
  24. package/composables/useLocal.ts +41 -0
  25. package/composables/useLocalAuth.ts +109 -0
  26. package/composables/useOrg.ts +127 -0
  27. package/composables/usePermission.ts +54 -0
  28. package/composables/useRecapPermission.ts +26 -0
  29. package/composables/useRole.ts +73 -0
  30. package/composables/useUser.ts +93 -0
  31. package/composables/useUtils.ts +109 -0
  32. package/nuxt.config.ts +60 -0
  33. package/package.json +33 -0
  34. package/plugins/API.ts +44 -0
  35. package/plugins/vuetify.ts +41 -0
  36. package/tsconfig.json +3 -0
  37. package/types/local.d.ts +63 -0
  38. package/types/permission.d.ts +24 -0
  39. package/types/role.d.ts +11 -0
@@ -0,0 +1,8 @@
1
+ # Changesets
2
+
3
+ Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4
+ with multi-package repos, or single-package repos to help you version and publish your code. You can
5
+ find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6
+
7
+ We have a quick list of common questions to get you started engaging with this project in
8
+ [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@changesets/config@3.0.5/schema.json",
3
+ "changelog": "@changesets/cli/changelog",
4
+ "commit": false,
5
+ "fixed": [],
6
+ "linked": [],
7
+ "access": "restricted",
8
+ "baseBranch": "main",
9
+ "updateInternalDependencies": "patch",
10
+ "ignore": []
11
+ }
package/.editorconfig ADDED
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_size = 2
5
+ indent_style = space
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
@@ -0,0 +1,17 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches:
5
+ - "**"
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-node@v4
13
+ with:
14
+ node-version: 20.x
15
+ cache: "yarn"
16
+ - run: yarn install --frozen-lockfile && yarn dev:prepare
17
+ - run: yarn build
@@ -0,0 +1,39 @@
1
+ name: Publish
2
+ on:
3
+ workflow_run:
4
+ workflows: [CI]
5
+ branches: [main]
6
+ types: [completed]
7
+
8
+ concurrency: ${{ github.workflow }}-${{ github.ref }}
9
+
10
+ permissions:
11
+ contents: write
12
+ pull-requests: write
13
+
14
+ jobs:
15
+ publish:
16
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - uses: actions/setup-node@v4
22
+ with:
23
+ node-version: 20.x
24
+ cache: "yarn" # Use yarn for caching
25
+ cache-dependency-path: yarn.lock # Cache Yarn lockfile
26
+
27
+ - run: yarn install --immutable # Install dependencies with immutable lockfile
28
+
29
+ - name: Create .npmrc for publishing
30
+ run: |
31
+ echo '//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}' > ~/.npmrc
32
+
33
+ - name: Create Release Pull Request or Publish
34
+ id: changesets
35
+ uses: changesets/action@v1
36
+ with:
37
+ publish: yarn release # Use yarn for publishing
38
+ env:
39
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
package/.nuxtrc ADDED
@@ -0,0 +1 @@
1
+ typescript.includeWorkspace = true
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <v-app>
3
+ <LayoutHeader />
4
+
5
+ <LayoutNavigationDrawer :navigation-items="navigationItems"/>
6
+
7
+ <v-main>
8
+ <slot />
9
+ </v-main>
10
+ </v-app>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ const navigationItems = computed(() => {
15
+ const items: Array<TNavigationItem> = [];
16
+ items.push(
17
+ {
18
+ title: "Create new request",
19
+ route: { name: "index" },
20
+ icon: "mdi-plus",
21
+ },
22
+ {
23
+ title: "Requests",
24
+ route: { name: "index" },
25
+ icon: "mdi-account-circle",
26
+ },
27
+ {
28
+ title: "Draft",
29
+ route: { name: "index" },
30
+ icon: "mdi-account-circle",
31
+ }
32
+ );
33
+
34
+ return items;
35
+ });
36
+ </script>
@@ -0,0 +1,6 @@
1
+ // @ts-check
2
+ import withNuxt from './.nuxt/eslint.config.mjs'
3
+
4
+ export default withNuxt(
5
+ // Your custom configs here
6
+ )
@@ -0,0 +1,22 @@
1
+ export default defineNuxtConfig({
2
+ extends: [".."],
3
+ modules: ["@nuxt/eslint"],
4
+ compatibilityDate: "2024-11-03",
5
+
6
+ runtimeConfig: {
7
+ public: {
8
+ cookieConfig: {
9
+ domain: (process.env.DOMAIN as string) ?? "localhost",
10
+ secure: true,
11
+ maxAge: 30 * 24 * 60 * 60,
12
+ },
13
+ APP_NAME: (process.env.APP_NAME as string) ?? "App",
14
+ APP_NAME_ROUTE: (process.env.APP_NAME_ROUTE as string) ?? "index",
15
+ APP_ACCOUNT: (process.env.APP_ACCOUNT as string) ?? "",
16
+ API_DO_STORAGE_ENDPOINT:
17
+ (process.env.API_DO_STORAGE_ENDPOINT as string) ?? "",
18
+ APP_ADMIN: (process.env.APP_ADMIN as string) ?? "",
19
+ APP_CBA_RECAP: (process.env.APP_CBA_RECAP as string) ?? "",
20
+ },
21
+ },
22
+ });
package/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # @iservice365/layer-common
2
+
3
+ ## 0.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 1a370ad: Init
8
+ - 3ccdbc0: Init
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # Nuxt Layer Starter
2
+
3
+ Create Nuxt extendable layer with this GitHub template.
4
+
5
+ ## Setup
6
+
7
+ Make sure to install the dependencies:
8
+
9
+ ```bash
10
+ pnpm install
11
+ ```
12
+
13
+ ## Working on your layer
14
+
15
+ Your layer is at the root of this repository, it is exactly like a regular Nuxt project, except you can publish it on NPM.
16
+
17
+ The `.playground` directory should help you on trying your layer during development.
18
+
19
+ Running `pnpm dev` will prepare and boot `.playground` directory, which imports your layer itself.
20
+
21
+ ## Distributing your layer
22
+
23
+ Your Nuxt layer is shaped exactly the same as any other Nuxt project, except you can publish it on NPM.
24
+
25
+ To do so, you only have to check if `files` in `package.json` are valid, then run:
26
+
27
+ ```bash
28
+ npm publish --access public
29
+ ```
30
+
31
+ Once done, your users will only have to run:
32
+
33
+ ```bash
34
+ npm install --save your-layer
35
+ ```
36
+
37
+ Then add the dependency to their `extends` in `nuxt.config`:
38
+
39
+ ```ts
40
+ defineNuxtConfig({
41
+ extends: 'your-layer'
42
+ })
43
+ ```
44
+
45
+ ## Development Server
46
+
47
+ Start the development server on http://localhost:3000
48
+
49
+ ```bash
50
+ pnpm dev
51
+ ```
52
+
53
+ ## Production
54
+
55
+ Build the application for production:
56
+
57
+ ```bash
58
+ pnpm build
59
+ ```
60
+
61
+ Or statically generate it with:
62
+
63
+ ```bash
64
+ pnpm generate
65
+ ```
66
+
67
+ Locally preview production build:
68
+
69
+ ```bash
70
+ pnpm preview
71
+ ```
72
+
73
+ Checkout the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
package/app.vue ADDED
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <h1>Common</h1>
3
+ </template>
@@ -0,0 +1,139 @@
1
+ <template>
2
+ <v-input
3
+ :label="label"
4
+ :error="!!errorMessage"
5
+ :error-messages="errorMessage"
6
+ :hide-details="readOnly ?? !!value"
7
+ class="btn-input-file"
8
+ >
9
+ <template #default>
10
+ <v-row no-gutters>
11
+ <v-col v-if="value || readOnly" cols="12">
12
+ <v-row no-gutters>
13
+ <v-card
14
+ variant="outlined"
15
+ border="thin"
16
+ class="px-4 text-caption font-weight-medium"
17
+ :rounded="readOnly ? '' : '0 s'"
18
+ height="36"
19
+ @click="emit('click:view')"
20
+ >
21
+ <v-row no-gutters class="fill-height" align="center">
22
+ {{ value ? "View attachment" : "No file attached" }}
23
+ </v-row>
24
+ </v-card>
25
+ <v-card
26
+ v-if="!readOnly"
27
+ variant="outlined"
28
+ border="s-0 thin"
29
+ rounded="0 e"
30
+ class="px-4 d-inline"
31
+ height="36"
32
+ @click="emit('click:close')"
33
+ >
34
+ <v-row no-gutters class="fill-height" align="center">
35
+ <v-icon size="small"> mdi-close </v-icon>
36
+ </v-row>
37
+ </v-card>
38
+ </v-row>
39
+ </v-col>
40
+
41
+ <v-col v-else cols="12">
42
+ <v-btn
43
+ variant="outlined"
44
+ border="thin"
45
+ class="text-none"
46
+ :prepend-icon="value ? '' : 'mdi-tray-arrow-up'"
47
+ :disabled="loading"
48
+ :loading="loading"
49
+ @click="selectAttachment"
50
+ >
51
+ Add file
52
+ </v-btn>
53
+ </v-col>
54
+ </v-row>
55
+
56
+ <v-file-input
57
+ v-show="false"
58
+ v-model="attachment"
59
+ multiple
60
+ accept="image/*"
61
+ :class="`attachment-input-${inputClass}`"
62
+ :name="name + 'custom-input-file'"
63
+ @change="uploadAttachment"
64
+ />
65
+ </template>
66
+ </v-input>
67
+ </template>
68
+
69
+ <script setup lang="ts">
70
+ const value = defineModel<string>({ required: true, default: "" });
71
+ const attachment = ref<File | null>(null);
72
+ const loading = ref(false);
73
+
74
+ const emit = defineEmits(["click:view", "click:close", "upload"]);
75
+
76
+ const { addFile } = useFile();
77
+ const inputClass = Date.now().toString();
78
+
79
+ function selectAttachment() {
80
+ const input = document.querySelector(
81
+ `.attachment-input-${inputClass} input`
82
+ ) as HTMLInputElement;
83
+ input.click();
84
+ }
85
+
86
+ async function uploadAttachment(e: Event) {
87
+ loading.value = true;
88
+ const files = (e.target as HTMLInputElement).files;
89
+
90
+ if (files && files.length > 0) {
91
+ const file = files[0];
92
+
93
+ try {
94
+ const res = await addFile(file);
95
+ value.value = res.id as string;
96
+ await emit("upload", res);
97
+ } catch (error) {
98
+ console.log(error);
99
+ }
100
+ } else {
101
+ console.log("No file selected");
102
+ }
103
+ loading.value = false;
104
+ }
105
+
106
+ // Other props (optional)
107
+ const { label, rules, name, readOnly } = defineProps({
108
+ label: {
109
+ type: String,
110
+ default: "Rating",
111
+ },
112
+ // Array of validation functions: (number) => true | string
113
+ rules: {
114
+ type: Array<Function>,
115
+ default: () => [],
116
+ },
117
+ name: {
118
+ type: String,
119
+ required: true,
120
+ default: "button-upload-file",
121
+ },
122
+ readOnly: {
123
+ type: Boolean,
124
+ default: false,
125
+ },
126
+ });
127
+
128
+ /**
129
+ * Compute the first failed validation rule, if any.
130
+ * Each rule returns true (if valid) or a string (if invalid).
131
+ */
132
+ const errorMessage = computed(() => {
133
+ for (const rule of rules) {
134
+ const result = rule(attachment.value || value.value);
135
+ return typeof result === "string" ? result : null;
136
+ }
137
+ return null;
138
+ });
139
+ </script>
@@ -0,0 +1,177 @@
1
+ <template>
2
+ <v-input
3
+ :error="!!validationErrMsg"
4
+ :error-messages="validationErrMsg"
5
+ hide-details="auto"
6
+ :name="name + 'custom-input-date'"
7
+ :disabled="props.disabled"
8
+ >
9
+ <template #default>
10
+ <v-row>
11
+ <v-col cols="12" lg="6" md="6">
12
+ <v-select
13
+ v-model="month"
14
+ :items="props.months"
15
+ label="Month"
16
+ density="comfortable"
17
+ :name="props.name + 'custom-input-date-month'"
18
+ hide-details
19
+ :error="!!validationErrMsg"
20
+ :disabled="props.disabled"
21
+ />
22
+ </v-col>
23
+
24
+ <v-col cols="12" lg="3" md="3">
25
+ <v-text-field
26
+ v-model.number="day"
27
+ type="number"
28
+ label="Day"
29
+ hide-details
30
+ placeholder="DD"
31
+ density="comfortable"
32
+ :name="props.name + 'custom-input-date-day'"
33
+ :error="!!validationErrMsg"
34
+ :disabled="props.disabled"
35
+ />
36
+ </v-col>
37
+
38
+ <v-col cols="12" lg="3" md="3">
39
+ <v-text-field
40
+ v-model.number="year"
41
+ type="number"
42
+ label="Year"
43
+ hide-details
44
+ placeholder="YYYY"
45
+ density="comfortable"
46
+ :name="props.name + 'custom-input-date-year'"
47
+ :error="!!validationErrMsg"
48
+ :disabled="props.disabled"
49
+ />
50
+ </v-col>
51
+ </v-row>
52
+ </template>
53
+ </v-input>
54
+ </template>
55
+
56
+ <script setup lang="ts">
57
+ const month = defineModel("month", { default: "" });
58
+ const day = defineModel("day", { default: 0 });
59
+ const year = defineModel("year", { default: 0 });
60
+
61
+ const props = defineProps({
62
+ months: {
63
+ type: Array,
64
+ default: [
65
+ "January",
66
+ "February",
67
+ "March",
68
+ "April",
69
+ "May",
70
+ "June",
71
+ "July",
72
+ "August",
73
+ "September",
74
+ "October",
75
+ "November",
76
+ "December",
77
+ ],
78
+ },
79
+ name: {
80
+ type: String,
81
+ default: "input-date-combo",
82
+ },
83
+ disabled: {
84
+ type: Boolean,
85
+ default: false,
86
+ },
87
+ });
88
+
89
+ const isLeapYear = (year: number): boolean =>
90
+ (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
91
+
92
+ const monthMap: Record<string, number> = {
93
+ January: 1,
94
+ February: 2,
95
+ March: 3,
96
+ April: 4,
97
+ May: 5,
98
+ June: 6,
99
+ July: 7,
100
+ August: 8,
101
+ September: 9,
102
+ October: 10,
103
+ November: 11,
104
+ December: 12,
105
+ };
106
+
107
+ const validateBirthDate = (): string => {
108
+ const _month = monthMap[month.value];
109
+ const _day = day.value;
110
+ const _year = year.value;
111
+
112
+ const errorMessage = "Enter a valid date";
113
+
114
+ if (
115
+ !_month ||
116
+ !_day ||
117
+ !_year ||
118
+ _year < 1904 ||
119
+ _year > new Date().getFullYear()
120
+ ) {
121
+ return errorMessage;
122
+ }
123
+
124
+ const daysInMonth = [
125
+ 31,
126
+ isLeapYear(_year) ? 29 : 28,
127
+ 31,
128
+ 30,
129
+ 31,
130
+ 30,
131
+ 31,
132
+ 31,
133
+ 30,
134
+ 31,
135
+ 30,
136
+ 31,
137
+ ];
138
+
139
+ if (_day < 1 || _day > daysInMonth[_month - 1]) {
140
+ return errorMessage;
141
+ }
142
+
143
+ if (!_month || !_day || !_year) {
144
+ return errorMessage;
145
+ }
146
+
147
+ return "";
148
+ };
149
+
150
+ const validationErrMsg = ref("");
151
+
152
+ const date = computed(() => {
153
+ return {
154
+ day: day.value,
155
+ month: month.value,
156
+ year: year.value,
157
+ };
158
+ });
159
+
160
+ validationErrMsg.value = validateBirthDate();
161
+
162
+ const disabled = computed(() => props.disabled);
163
+
164
+ watch(disabled, (curr) => {
165
+ if (curr) {
166
+ validationErrMsg.value = validateBirthDate();
167
+ }
168
+ });
169
+
170
+ watch(
171
+ date,
172
+ () => {
173
+ validationErrMsg.value = validateBirthDate();
174
+ },
175
+ { deep: true }
176
+ );
177
+ </script>
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <v-text-field
3
+ id="_password"
4
+ v-model="password"
5
+ :type="showPassword ? 'text' : 'password'"
6
+ :append-inner-icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
7
+ v-bind="$attrs"
8
+ autocomplete="off"
9
+ @click:append-inner="togglePasswordVisibility"
10
+ />
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ // Define the props for the v-model
15
+ const password = defineModel({ default: "" });
16
+
17
+ // Control password visibility
18
+ const showPassword = ref(false);
19
+ const togglePasswordVisibility = () => {
20
+ showPassword.value = !showPassword.value;
21
+ };
22
+ </script>
@@ -0,0 +1,18 @@
1
+ <template>
2
+ <span class="text-subtitle-2 font-weight-medium">
3
+ {{ title }} <span v-if="props.required" class="text-error">*</span>
4
+ </span>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ const props = defineProps({
9
+ title: {
10
+ type: String,
11
+ required: true,
12
+ },
13
+ required: {
14
+ type: Boolean,
15
+ default: false,
16
+ },
17
+ });
18
+ </script>