@illuminateeducation/dna-atd-frontend 1.0.1-DNAATD-2189.0
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/README.md +77 -0
- package/dist/.vite/manifest.json +87 -0
- package/dist/assets/AdminLayout.css +1 -0
- package/dist/assets/AdminLayout.js +1 -0
- package/dist/assets/CustomizationView.css +1 -0
- package/dist/assets/CustomizationView.js +1 -0
- package/dist/assets/HomeView.css +1 -0
- package/dist/assets/HomeView.js +1 -0
- package/dist/assets/NotFoundView.css +1 -0
- package/dist/assets/NotFoundView.js +1 -0
- package/dist/assets/ValidationView.css +1 -0
- package/dist/assets/ValidationView.js +1 -0
- package/dist/assets/_plugin-vue_export-helper.js +1 -0
- package/dist/assets/index.css +1 -0
- package/dist/assets/index.js +2 -0
- package/dist/favicon.ico +0 -0
- package/dist/index.html +14 -0
- package/index.js +1 -0
- package/package.json +64 -0
- package/src/App.vue +68 -0
- package/src/__tests__/App.spec.js +26 -0
- package/src/components/common/BaseButton.vue +20 -0
- package/src/components/common/BaseInput.vue +27 -0
- package/src/components/common/BaseModal.vue +37 -0
- package/src/composables/useAsync.js +34 -0
- package/src/composables/useClickOutside.js +29 -0
- package/src/composables/useForm.js +89 -0
- package/src/composables/useLocalStorage.js +51 -0
- package/src/composables/useWindowSize.js +30 -0
- package/src/config/app.config.js +79 -0
- package/src/features/admin/customization/composables/useCustomization.js +19 -0
- package/src/features/admin/customization/store/customizationStore.js +30 -0
- package/src/features/admin/customization/views/CustomizationView.vue +17 -0
- package/src/features/admin/validation/composables/useValidation.js +18 -0
- package/src/features/admin/validation/store/validationStore.js +25 -0
- package/src/features/admin/validation/views/ValidationView.vue +17 -0
- package/src/index.js +53 -0
- package/src/layouts/AdminLayout.vue +146 -0
- package/src/main.js +41 -0
- package/src/router/index.js +57 -0
- package/src/services/apiService.js +72 -0
- package/src/services/integration.js +59 -0
- package/src/services/phpIntegration.js +1 -0
- package/src/stores/counter.js +12 -0
- package/src/utils/helpers.js +119 -0
- package/src/utils/validators.js +131 -0
- package/src/views/HomeView.vue +121 -0
- package/src/views/NotFoundView.vue +56 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import { createMemoryHistory, createRouter } from 'vue-router'
|
|
4
|
+
import App from '../App.vue'
|
|
5
|
+
|
|
6
|
+
describe('App', () => {
|
|
7
|
+
it('renders properly', () => {
|
|
8
|
+
const router = createRouter({
|
|
9
|
+
history: createMemoryHistory(),
|
|
10
|
+
routes: [
|
|
11
|
+
{
|
|
12
|
+
path: '/',
|
|
13
|
+
component: { template: '<div>Home</div>' }
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const wrapper = mount(App, {
|
|
19
|
+
global: {
|
|
20
|
+
plugins: [router]
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
expect(wrapper.find('#app').exists()).toBe(true)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button class="btn" @click="$emit('click')">
|
|
3
|
+
<slot />
|
|
4
|
+
</button>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup>
|
|
8
|
+
defineEmits(['click'])
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<style scoped>
|
|
12
|
+
.btn {
|
|
13
|
+
padding: 0.5rem 1rem;
|
|
14
|
+
border: 1px solid #ddd;
|
|
15
|
+
border-radius: 4px;
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
background: white;
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
20
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<input
|
|
3
|
+
:value="modelValue"
|
|
4
|
+
class="input"
|
|
5
|
+
@input="$emit('update:modelValue', $event.target.value)"
|
|
6
|
+
/>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup>
|
|
10
|
+
defineProps({
|
|
11
|
+
modelValue: {
|
|
12
|
+
type: String,
|
|
13
|
+
default: ''
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
defineEmits(['update:modelValue'])
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<style scoped>
|
|
21
|
+
.input {
|
|
22
|
+
padding: 0.5rem;
|
|
23
|
+
border: 1px solid #ddd;
|
|
24
|
+
border-radius: 4px;
|
|
25
|
+
}
|
|
26
|
+
</style>
|
|
27
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="show" class="modal">
|
|
3
|
+
<div class="modal-content">
|
|
4
|
+
<slot />
|
|
5
|
+
</div>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup>
|
|
10
|
+
defineProps({
|
|
11
|
+
show: {
|
|
12
|
+
type: Boolean,
|
|
13
|
+
default: false
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<style scoped>
|
|
19
|
+
.modal {
|
|
20
|
+
position: fixed;
|
|
21
|
+
top: 0;
|
|
22
|
+
left: 0;
|
|
23
|
+
width: 100%;
|
|
24
|
+
height: 100%;
|
|
25
|
+
background: rgba(0, 0, 0, 0.5);
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.modal-content {
|
|
32
|
+
background: white;
|
|
33
|
+
padding: 2rem;
|
|
34
|
+
border-radius: 4px;
|
|
35
|
+
}
|
|
36
|
+
</style>
|
|
37
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ref, onMounted, onUnmounted } from 'vue'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Composable for handling async operations
|
|
5
|
+
* @param {Function} asyncFunction - Async function to execute
|
|
6
|
+
* @returns {Object}
|
|
7
|
+
*/
|
|
8
|
+
export function useAsync(asyncFunction) {
|
|
9
|
+
const data = ref(null)
|
|
10
|
+
const error = ref(null)
|
|
11
|
+
const isLoading = ref(false)
|
|
12
|
+
|
|
13
|
+
const execute = async (...args) => {
|
|
14
|
+
isLoading.value = true
|
|
15
|
+
error.value = null
|
|
16
|
+
try {
|
|
17
|
+
data.value = await asyncFunction(...args)
|
|
18
|
+
return data.value
|
|
19
|
+
} catch (err) {
|
|
20
|
+
error.value = err
|
|
21
|
+
throw err
|
|
22
|
+
} finally {
|
|
23
|
+
isLoading.value = false
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
data,
|
|
29
|
+
error,
|
|
30
|
+
isLoading,
|
|
31
|
+
execute
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ref, onMounted, onUnmounted } from 'vue'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Composable for detecting clicks outside an element
|
|
5
|
+
* @param {Function} callback - Function to call when clicked outside
|
|
6
|
+
* @returns {Object}
|
|
7
|
+
*/
|
|
8
|
+
export function useClickOutside(callback) {
|
|
9
|
+
const elementRef = ref(null)
|
|
10
|
+
|
|
11
|
+
const handleClickOutside = (event) => {
|
|
12
|
+
if (elementRef.value && !elementRef.value.contains(event.target)) {
|
|
13
|
+
callback()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
onMounted(() => {
|
|
18
|
+
document.addEventListener('click', handleClickOutside)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
onUnmounted(() => {
|
|
22
|
+
document.removeEventListener('click', handleClickOutside)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
elementRef
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { ref, computed } from 'vue'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Composable for form validation
|
|
5
|
+
* @param {Object} initialValues - Initial form values
|
|
6
|
+
* @param {Object} validationRules - Validation rules for each field
|
|
7
|
+
* @returns {Object}
|
|
8
|
+
*/
|
|
9
|
+
export function useForm(initialValues = {}, validationRules = {}) {
|
|
10
|
+
const formData = ref({ ...initialValues })
|
|
11
|
+
const errors = ref({})
|
|
12
|
+
const touched = ref({})
|
|
13
|
+
|
|
14
|
+
const isValid = computed(() => {
|
|
15
|
+
return Object.keys(errors.value).length === 0
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const validateField = (fieldName) => {
|
|
19
|
+
const value = formData.value[fieldName]
|
|
20
|
+
const rules = validationRules[fieldName]
|
|
21
|
+
|
|
22
|
+
if (!rules) return true
|
|
23
|
+
|
|
24
|
+
for (const rule of rules) {
|
|
25
|
+
const result = rule.validator(value)
|
|
26
|
+
if (!result) {
|
|
27
|
+
errors.value[fieldName] = rule.message
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
delete errors.value[fieldName]
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const validateForm = () => {
|
|
37
|
+
errors.value = {}
|
|
38
|
+
let isFormValid = true
|
|
39
|
+
|
|
40
|
+
Object.keys(validationRules).forEach(fieldName => {
|
|
41
|
+
if (!validateField(fieldName)) {
|
|
42
|
+
isFormValid = false
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return isFormValid
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const handleBlur = (fieldName) => {
|
|
50
|
+
touched.value[fieldName] = true
|
|
51
|
+
validateField(fieldName)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const handleChange = (fieldName, value) => {
|
|
55
|
+
formData.value[fieldName] = value
|
|
56
|
+
if (touched.value[fieldName]) {
|
|
57
|
+
validateField(fieldName)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const resetForm = () => {
|
|
62
|
+
formData.value = { ...initialValues }
|
|
63
|
+
errors.value = {}
|
|
64
|
+
touched.value = {}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const setFieldValue = (fieldName, value) => {
|
|
68
|
+
formData.value[fieldName] = value
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const setFieldError = (fieldName, error) => {
|
|
72
|
+
errors.value[fieldName] = error
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
formData,
|
|
77
|
+
errors,
|
|
78
|
+
touched,
|
|
79
|
+
isValid,
|
|
80
|
+
validateField,
|
|
81
|
+
validateForm,
|
|
82
|
+
handleBlur,
|
|
83
|
+
handleChange,
|
|
84
|
+
resetForm,
|
|
85
|
+
setFieldValue,
|
|
86
|
+
setFieldError
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ref, onMounted, onUnmounted } from 'vue'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Composable for managing localStorage
|
|
5
|
+
* @param {string} key - Storage key
|
|
6
|
+
* @param {*} defaultValue - Default value if key doesn't exist
|
|
7
|
+
* @returns {Object}
|
|
8
|
+
*/
|
|
9
|
+
export function useLocalStorage(key, defaultValue = null) {
|
|
10
|
+
const data = ref(defaultValue)
|
|
11
|
+
|
|
12
|
+
const read = () => {
|
|
13
|
+
try {
|
|
14
|
+
const item = window.localStorage.getItem(key)
|
|
15
|
+
return item ? JSON.parse(item) : defaultValue
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.error(`Error reading localStorage key "${key}":`, error)
|
|
18
|
+
return defaultValue
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const write = (value) => {
|
|
23
|
+
try {
|
|
24
|
+
data.value = value
|
|
25
|
+
window.localStorage.setItem(key, JSON.stringify(value))
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error(`Error writing localStorage key "${key}":`, error)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const remove = () => {
|
|
32
|
+
try {
|
|
33
|
+
window.localStorage.removeItem(key)
|
|
34
|
+
data.value = defaultValue
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error(`Error removing localStorage key "${key}":`, error)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Initialize
|
|
41
|
+
onMounted(() => {
|
|
42
|
+
data.value = read()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
data,
|
|
47
|
+
write,
|
|
48
|
+
remove
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ref, onMounted, onUnmounted } from 'vue'
|
|
2
|
+
import { debounce } from '../utils/helpers'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Composable for tracking window size
|
|
6
|
+
* @returns {Object}
|
|
7
|
+
*/
|
|
8
|
+
export function useWindowSize() {
|
|
9
|
+
const width = ref(window.innerWidth)
|
|
10
|
+
const height = ref(window.innerHeight)
|
|
11
|
+
|
|
12
|
+
const handleResize = debounce(() => {
|
|
13
|
+
width.value = window.innerWidth
|
|
14
|
+
height.value = window.innerHeight
|
|
15
|
+
}, 200)
|
|
16
|
+
|
|
17
|
+
onMounted(() => {
|
|
18
|
+
window.addEventListener('resize', handleResize)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
onUnmounted(() => {
|
|
22
|
+
window.removeEventListener('resize', handleResize)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
width,
|
|
27
|
+
height
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const appConfig = {
|
|
6
|
+
// Application name
|
|
7
|
+
name: 'DNA ATD Frontend',
|
|
8
|
+
|
|
9
|
+
// Version
|
|
10
|
+
version: '1.0.0',
|
|
11
|
+
|
|
12
|
+
// API Configuration
|
|
13
|
+
api: {
|
|
14
|
+
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api',
|
|
15
|
+
timeout: 30000,
|
|
16
|
+
headers: {
|
|
17
|
+
'Content-Type': 'application/json'
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
// Theme Configuration
|
|
22
|
+
theme: {
|
|
23
|
+
default: 'light',
|
|
24
|
+
available: ['light', 'dark', 'auto']
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// Layout Configuration
|
|
28
|
+
layout: {
|
|
29
|
+
sidebarWidth: 250,
|
|
30
|
+
headerHeight: 64,
|
|
31
|
+
footerHeight: 48
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
// Pagination
|
|
35
|
+
pagination: {
|
|
36
|
+
defaultPageSize: 10,
|
|
37
|
+
pageSizeOptions: [10, 20, 50, 100]
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// Date Format
|
|
41
|
+
dateFormat: {
|
|
42
|
+
short: 'MMM DD, YYYY',
|
|
43
|
+
long: 'MMMM DD, YYYY HH:mm',
|
|
44
|
+
time: 'HH:mm:ss'
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// Storage Keys
|
|
48
|
+
storageKeys: {
|
|
49
|
+
theme: 'app_theme',
|
|
50
|
+
locale: 'app_locale',
|
|
51
|
+
token: 'app_token',
|
|
52
|
+
user: 'app_user'
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// Feature Flags
|
|
56
|
+
features: {
|
|
57
|
+
darkMode: true,
|
|
58
|
+
notifications: true,
|
|
59
|
+
analytics: false
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Validation Rules
|
|
63
|
+
validation: {
|
|
64
|
+
password: {
|
|
65
|
+
minLength: 8,
|
|
66
|
+
requireUppercase: true,
|
|
67
|
+
requireLowercase: true,
|
|
68
|
+
requireNumbers: true,
|
|
69
|
+
requireSpecialChars: true
|
|
70
|
+
},
|
|
71
|
+
username: {
|
|
72
|
+
minLength: 3,
|
|
73
|
+
maxLength: 20
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default appConfig
|
|
79
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { storeToRefs } from 'pinia'
|
|
2
|
+
import { useCustomizationStore } from '../store/customizationStore'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Composable for customization feature
|
|
6
|
+
*/
|
|
7
|
+
export function useCustomization() {
|
|
8
|
+
const customizationStore = useCustomizationStore()
|
|
9
|
+
const { settings, isLoading } = storeToRefs(customizationStore)
|
|
10
|
+
const { fetchSettings, updateSettings } = customizationStore
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
settings,
|
|
14
|
+
isLoading,
|
|
15
|
+
fetchSettings,
|
|
16
|
+
updateSettings
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Customization Store - Basic Example
|
|
6
|
+
*/
|
|
7
|
+
export const useCustomizationStore = defineStore('customization', () => {
|
|
8
|
+
// State
|
|
9
|
+
const settings = ref({})
|
|
10
|
+
const isLoading = ref(false)
|
|
11
|
+
|
|
12
|
+
// Actions
|
|
13
|
+
const fetchSettings = async () => {
|
|
14
|
+
isLoading.value = true
|
|
15
|
+
// Add your API call here
|
|
16
|
+
isLoading.value = false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const updateSettings = (newSettings) => {
|
|
20
|
+
settings.value = { ...settings.value, ...newSettings }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
settings,
|
|
25
|
+
isLoading,
|
|
26
|
+
fetchSettings,
|
|
27
|
+
updateSettings
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="customization-view">
|
|
3
|
+
<h2>Customization Module</h2>
|
|
4
|
+
<p>Customization feature content goes here.</p>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup>
|
|
9
|
+
// Customization module - basic implementation
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<style scoped>
|
|
13
|
+
.customization-view {
|
|
14
|
+
padding: 2rem;
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { storeToRefs } from 'pinia'
|
|
2
|
+
import { useValidationStore } from '../store/validationStore'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Composable for validation feature
|
|
6
|
+
*/
|
|
7
|
+
export function useValidation() {
|
|
8
|
+
const validationStore = useValidationStore()
|
|
9
|
+
const { data, isLoading } = storeToRefs(validationStore)
|
|
10
|
+
const { fetchData } = validationStore
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
data,
|
|
14
|
+
isLoading,
|
|
15
|
+
fetchData
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Validation Store - Basic Example
|
|
6
|
+
*/
|
|
7
|
+
export const useValidationStore = defineStore('validation', () => {
|
|
8
|
+
// State
|
|
9
|
+
const data = ref([])
|
|
10
|
+
const isLoading = ref(false)
|
|
11
|
+
|
|
12
|
+
// Actions
|
|
13
|
+
const fetchData = async () => {
|
|
14
|
+
isLoading.value = true
|
|
15
|
+
// Add your API call here
|
|
16
|
+
isLoading.value = false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
data,
|
|
21
|
+
isLoading,
|
|
22
|
+
fetchData
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="validation-view">
|
|
3
|
+
<h2>Validation Module</h2>
|
|
4
|
+
<p>Validation feature content goes here.</p>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup>
|
|
9
|
+
// Validation module - basic implementation
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<style scoped>
|
|
13
|
+
.validation-view {
|
|
14
|
+
padding: 2rem;
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
|
package/src/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
import { createPinia } from 'pinia'
|
|
3
|
+
import router from './router'
|
|
4
|
+
import App from './App.vue'
|
|
5
|
+
|
|
6
|
+
export function createDnaAtdApp(elementId = '#app') {
|
|
7
|
+
const app = createApp(App)
|
|
8
|
+
const pinia = createPinia()
|
|
9
|
+
app.use(pinia)
|
|
10
|
+
app.use(router)
|
|
11
|
+
return app.mount(elementId)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createDnaAtdAppInstance() {
|
|
15
|
+
const app = createApp(App)
|
|
16
|
+
const pinia = createPinia()
|
|
17
|
+
app.use(pinia)
|
|
18
|
+
app.use(router)
|
|
19
|
+
return app
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { default as App } from './App.vue'
|
|
23
|
+
export { default as router } from './router'
|
|
24
|
+
|
|
25
|
+
export { default as BaseButton } from './components/common/BaseButton.vue'
|
|
26
|
+
export { default as BaseInput } from './components/common/BaseInput.vue'
|
|
27
|
+
export { default as BaseModal } from './components/common/BaseModal.vue'
|
|
28
|
+
|
|
29
|
+
export { default as AdminLayout } from './layouts/AdminLayout.vue'
|
|
30
|
+
|
|
31
|
+
export { useAsync } from './composables/useAsync'
|
|
32
|
+
export { useForm } from './composables/useForm'
|
|
33
|
+
export { useClickOutside } from './composables/useClickOutside'
|
|
34
|
+
export { useLocalStorage } from './composables/useLocalStorage'
|
|
35
|
+
export { useWindowSize } from './composables/useWindowSize'
|
|
36
|
+
|
|
37
|
+
export { useValidationStore } from './features/admin/validation/store/validationStore'
|
|
38
|
+
export { useCustomizationStore } from './features/admin/customization/store/customizationStore'
|
|
39
|
+
|
|
40
|
+
export { useValidation } from './features/admin/validation/composables/useValidation'
|
|
41
|
+
export { useCustomization } from './features/admin/customization/composables/useCustomization'
|
|
42
|
+
|
|
43
|
+
export { default as ValidationView } from './features/admin/validation/views/ValidationView.vue'
|
|
44
|
+
export { default as CustomizationView } from './features/admin/customization/views/CustomizationView.vue'
|
|
45
|
+
|
|
46
|
+
export { default as apiService } from './services/apiService'
|
|
47
|
+
export { appConfig } from './config/app.config'
|
|
48
|
+
|
|
49
|
+
export * from './utils/helpers'
|
|
50
|
+
export * from './utils/validators'
|
|
51
|
+
|
|
52
|
+
export { default as HomeView } from './views/HomeView.vue'
|
|
53
|
+
export { default as NotFoundView } from './views/NotFoundView.vue'
|