@vue-skuilder/platform-ui 0.1.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 (108) hide show
  1. package/LICENCE +661 -0
  2. package/README.md +64 -0
  3. package/dist/assets/Roboto-Black-B0ZKieaB.woff +0 -0
  4. package/dist/assets/Roboto-Black-VhoA2qKx.woff2 +0 -0
  5. package/dist/assets/Roboto-BlackItalic-D0gSnuIb.woff +0 -0
  6. package/dist/assets/Roboto-BlackItalic-D4yie1YO.woff2 +0 -0
  7. package/dist/assets/Roboto-Bold-D9plYbeK.woff +0 -0
  8. package/dist/assets/Roboto-Bold-hN3duQhD.woff2 +0 -0
  9. package/dist/assets/Roboto-BoldItalic-BWDm51uc.woff2 +0 -0
  10. package/dist/assets/Roboto-BoldItalic-CyLKvOHD.woff +0 -0
  11. package/dist/assets/Roboto-Light-Cu-PAxXt.woff +0 -0
  12. package/dist/assets/Roboto-Light-DHTugVNA.woff2 +0 -0
  13. package/dist/assets/Roboto-LightItalic-CZg5kHIB.woff +0 -0
  14. package/dist/assets/Roboto-LightItalic-JQyp2Y3P.woff2 +0 -0
  15. package/dist/assets/Roboto-Medium-ByKogCTi.woff2 +0 -0
  16. package/dist/assets/Roboto-Medium-b81vv18W.woff +0 -0
  17. package/dist/assets/Roboto-MediumItalic-DFQ-RYa0.woff +0 -0
  18. package/dist/assets/Roboto-MediumItalic-i1eR0KbF.woff2 +0 -0
  19. package/dist/assets/Roboto-Regular-BX5l9hRW.woff +0 -0
  20. package/dist/assets/Roboto-Regular-C6rbFxYz.woff2 +0 -0
  21. package/dist/assets/Roboto-RegularItalic-BjnLZsam.woff +0 -0
  22. package/dist/assets/Roboto-RegularItalic-CvPUdkvM.woff2 +0 -0
  23. package/dist/assets/Roboto-Thin-BfJvJcog.woff +0 -0
  24. package/dist/assets/Roboto-Thin-NicBC1pN.woff2 +0 -0
  25. package/dist/assets/Roboto-ThinItalic-CKlCjrO_.woff2 +0 -0
  26. package/dist/assets/Roboto-ThinItalic-DnIWFxRE.woff +0 -0
  27. package/dist/assets/index-CQ-sNKGW.css +14 -0
  28. package/dist/assets/index-EbqpUgvM.js +161 -0
  29. package/dist/assets/materialdesignicons-webfont-B7mPwVP_.ttf +0 -0
  30. package/dist/assets/materialdesignicons-webfont-CSr8KVlo.eot +0 -0
  31. package/dist/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 +0 -0
  32. package/dist/assets/materialdesignicons-webfont-PXm3-2wK.woff +0 -0
  33. package/dist/assets/workbox-window.prod.es5-p40uij6f.js +1 -0
  34. package/dist/favicon.ico +0 -0
  35. package/dist/img/icons/safari-pinned-tab.svg +149 -0
  36. package/dist/index.html +19 -0
  37. package/dist/manifest.json +20 -0
  38. package/dist/manifest.webmanifest +1 -0
  39. package/dist/robots.txt +2 -0
  40. package/dist/sw.js +1 -0
  41. package/dist/workbox-1be04862.js +1 -0
  42. package/package.json +105 -0
  43. package/src/App.vue +156 -0
  44. package/src/ENVIRONMENT_VARS.ts +79 -0
  45. package/src/components/Classrooms/ClassroomCtrlPanel.vue +206 -0
  46. package/src/components/Classrooms/CreateClassroom.vue +159 -0
  47. package/src/components/Classrooms/JoinCode.vue +83 -0
  48. package/src/components/Courses/CourseCardBrowser.vue +365 -0
  49. package/src/components/Courses/CourseEditor.vue +164 -0
  50. package/src/components/Courses/CourseInformation.vue +164 -0
  51. package/src/components/Courses/CourseRouter.vue +116 -0
  52. package/src/components/Courses/CourseStubCard.vue +76 -0
  53. package/src/components/Courses/EloModeration.vue +122 -0
  54. package/src/components/Courses/TagInformation.vue +209 -0
  55. package/src/components/Edit/BulkImport/CardPreviewList.vue +345 -0
  56. package/src/components/Edit/BulkImportView.vue +633 -0
  57. package/src/components/Edit/CardBrowser.vue +79 -0
  58. package/src/components/Edit/ComponentRegistration/ComponentRegistration.vue +235 -0
  59. package/src/components/Edit/ComponentRegistration/UnregisteredComponentsTable.vue +19 -0
  60. package/src/components/Edit/CourseEditor.vue +162 -0
  61. package/src/components/Edit/NavigationStrategy/NavigationStrategyEditor.vue +170 -0
  62. package/src/components/Edit/NavigationStrategy/NavigationStrategyList.vue +92 -0
  63. package/src/components/Edit/TagsInput.vue +247 -0
  64. package/src/components/Edit/ViewableDataInputForm/DataInputForm.vue +524 -0
  65. package/src/components/Edit/ViewableDataInputForm/FieldInput.types.ts +33 -0
  66. package/src/components/Edit/ViewableDataInputForm/FieldInputs/AudioInput.vue +188 -0
  67. package/src/components/Edit/ViewableDataInputForm/FieldInputs/ChessPuzzleInput.vue +79 -0
  68. package/src/components/Edit/ViewableDataInputForm/FieldInputs/FieldInput.css +12 -0
  69. package/src/components/Edit/ViewableDataInputForm/FieldInputs/ImageInput.vue +231 -0
  70. package/src/components/Edit/ViewableDataInputForm/FieldInputs/IntegerInput.vue +49 -0
  71. package/src/components/Edit/ViewableDataInputForm/FieldInputs/MarkdownInput.vue +34 -0
  72. package/src/components/Edit/ViewableDataInputForm/FieldInputs/MediaDragDropUploader.vue +246 -0
  73. package/src/components/Edit/ViewableDataInputForm/FieldInputs/MidiInput.vue +113 -0
  74. package/src/components/Edit/ViewableDataInputForm/FieldInputs/NumberInput.vue +49 -0
  75. package/src/components/Edit/ViewableDataInputForm/FieldInputs/StringInput.vue +49 -0
  76. package/src/components/Edit/ViewableDataInputForm/FieldInputs/typeValidators.ts +49 -0
  77. package/src/components/Edit/ViewableDataInputForm/OptionsFieldInput.ts +161 -0
  78. package/src/components/Study/SessionConfiguration.vue +371 -0
  79. package/src/components/TextSwap.vue +65 -0
  80. package/src/components/User/UserStats.vue +30 -0
  81. package/src/dev/DataInputFormTester.vue +117 -0
  82. package/src/dev/readme.md +3 -0
  83. package/src/enums.ts +0 -0
  84. package/src/glyphs.txt +933 -0
  85. package/src/main.ts +45 -0
  86. package/src/plugins/vuetify.ts +41 -0
  87. package/src/registerServiceWorker.ts +18 -0
  88. package/src/router.ts +184 -0
  89. package/src/server/index.spec.ts +192 -0
  90. package/src/server/index.ts +71 -0
  91. package/src/shims-vue.d.ts +5 -0
  92. package/src/store.mock.ts +122 -0
  93. package/src/stores/useDataInputFormStore.ts +49 -0
  94. package/src/stores/useFieldInputStore.ts +191 -0
  95. package/src/types/shims-vuetify.d.ts +12 -0
  96. package/src/types/svg.d.ts +4 -0
  97. package/src/utils/bulkImport/index.ts +94 -0
  98. package/src/views/About.vue +29 -0
  99. package/src/views/Admin.vue +128 -0
  100. package/src/views/Classrooms.vue +258 -0
  101. package/src/views/Courses.vue +265 -0
  102. package/src/views/Home.vue +154 -0
  103. package/src/views/Login.vue +75 -0
  104. package/src/views/ReleaseNotes.vue +20 -0
  105. package/src/views/SignUp.vue +32 -0
  106. package/src/views/Study.vue +261 -0
  107. package/src/views/User.vue +109 -0
  108. package/src/vite-env.d.ts +1 -0
package/src/main.ts ADDED
@@ -0,0 +1,45 @@
1
+ import ENV from './ENVIRONMENT_VARS';
2
+
3
+ import 'roboto-fontface/css/roboto/roboto-fontface.css';
4
+ import { createApp } from 'vue';
5
+ import App from './App.vue';
6
+ import './registerServiceWorker';
7
+ import router from './router';
8
+ import { createPinia } from 'pinia';
9
+ import vuetify from './plugins/vuetify';
10
+ // `courses` imports - keep style import for initial page rendering
11
+ import '@vue-skuilder/courses/style';
12
+ // `db` import and initialization
13
+ import { initializeDataLayer } from '@vue-skuilder/db';
14
+
15
+ (async () => {
16
+ await initializeDataLayer({
17
+ type: 'pouch',
18
+ options: {
19
+ COUCHDB_SERVER_PROTOCOL: ENV.COUCHDB_SERVER_PROTOCOL,
20
+ COUCHDB_SERVER_URL: ENV.COUCHDB_SERVER_URL,
21
+ },
22
+ });
23
+
24
+ const pinia = createPinia();
25
+ const app = createApp(App);
26
+
27
+ // Dynamically import { allCourses }
28
+ const { allCourses: Courses } = await import('@vue-skuilder/courses');
29
+
30
+ // Register all view components globally
31
+ const viewComponents = Courses.allViewsRaw();
32
+ Object.entries(viewComponents).forEach(([name, component]) => {
33
+ app.component(name, component);
34
+ });
35
+
36
+ app.use(router);
37
+ app.use(vuetify);
38
+ app.use(pinia);
39
+
40
+ // Dynamically import piniaPlugin
41
+ const { piniaPlugin } = await import('@vue-skuilder/common-ui');
42
+ app.use(piniaPlugin, { pinia });
43
+
44
+ app.mount('#app');
45
+ })();
@@ -0,0 +1,41 @@
1
+ // src/plugins/vuetify.ts
2
+ import '@mdi/font/css/materialdesignicons.css';
3
+ import 'vuetify/styles';
4
+ import { createVuetify } from 'vuetify';
5
+ import * as components from 'vuetify/components';
6
+ import * as directives from 'vuetify/directives';
7
+
8
+ export default createVuetify({
9
+ components,
10
+ directives,
11
+ theme: {
12
+ defaultTheme: 'light',
13
+ themes: {
14
+ light: {
15
+ colors: {
16
+ primary: '#1976D2',
17
+ secondary: '#424242',
18
+ accent: '#82B1FF',
19
+ error: '#FF5252',
20
+ info: '#2196F3',
21
+ success: '#4CAF50',
22
+ warning: '#FFC107',
23
+ },
24
+ },
25
+ dark: {
26
+ colors: {
27
+ primary: '#2196F3',
28
+ secondary: '#424242',
29
+ accent: '#FF4081',
30
+ error: '#FF5252',
31
+ info: '#2196F3',
32
+ success: '#4CAF50',
33
+ warning: '#FFC107',
34
+ },
35
+ },
36
+ },
37
+ },
38
+ icons: {
39
+ defaultSet: 'mdi',
40
+ },
41
+ });
@@ -0,0 +1,18 @@
1
+ import { registerSW } from 'virtual:pwa-register';
2
+
3
+ if (import.meta.env.PROD) {
4
+ registerSW({
5
+ onNeedRefresh() {
6
+ console.log('New content is available; please refresh.');
7
+ },
8
+ onOfflineReady() {
9
+ console.log('Content has been cached for offline use.');
10
+ },
11
+ onRegistered() {
12
+ console.log('Service worker has been registered.');
13
+ },
14
+ onRegisterError(error) {
15
+ console.error('Error during service worker registration:', error);
16
+ },
17
+ });
18
+ }
package/src/router.ts ADDED
@@ -0,0 +1,184 @@
1
+ import { MarkdownRenderer } from '@vue-skuilder/common-ui';
2
+ import { createRouter, createWebHistory } from 'vue-router';
3
+ import ClassroomCtrlPanel from './components/Classrooms/ClassroomCtrlPanel.vue';
4
+ import JoinCode from './components/Classrooms/JoinCode.vue';
5
+ import CourseRouter from './components/Courses/CourseRouter.vue';
6
+ import ELOModerator from './components/Courses/EloModeration.vue';
7
+ import TagInformation from './components/Courses/TagInformation.vue';
8
+ import CourseEditor from './components/Edit/CourseEditor.vue';
9
+ import Stats from './components/User/UserStats.vue';
10
+ import About from './views/About.vue';
11
+ import Admin from './views/Admin.vue';
12
+ import Classrooms from './views/Classrooms.vue';
13
+ import Courses from './views/Courses.vue';
14
+ import Home from './views/Home.vue';
15
+ import Login from './views/Login.vue';
16
+ import ReleaseNotes from './views/ReleaseNotes.vue';
17
+ import SignUp from './views/SignUp.vue';
18
+ import Study from './views/Study.vue';
19
+ import User from './views/User.vue';
20
+ import DataInputFormTester from './dev/DataInputFormTester.vue';
21
+
22
+ const router = createRouter({
23
+ history: createWebHistory(),
24
+ // mode: 'history', // deprecated in Vue 3 / Vue Router 4
25
+
26
+ routes: [
27
+ // {
28
+ // path: '/debug/:component',
29
+ // name: 'componentPreviews',
30
+ // component: components[component]
31
+ // }
32
+ // todo:
33
+ //
34
+ // beforeEnter: () => authenticateAdmin ?
35
+ //
36
+ // const components: Component[] = [];
37
+ {
38
+ path: '/dif/:pathMatch(.*)',
39
+ name: 'testThePathComponent',
40
+ component: DataInputFormTester,
41
+ props: true,
42
+ },
43
+ {
44
+ path: '/md',
45
+ component: MarkdownRenderer,
46
+ },
47
+ {
48
+ path: '/',
49
+ alias: ['/home'],
50
+ name: 'home',
51
+ component: Home,
52
+ },
53
+ {
54
+ path: '/about',
55
+ name: 'about',
56
+ component: About,
57
+ },
58
+ {
59
+ path: '/login',
60
+ name: 'login',
61
+ component: Login,
62
+ },
63
+ {
64
+ path: '/signup',
65
+ name: 'signup',
66
+ component: SignUp,
67
+ },
68
+ {
69
+ path: '/notes',
70
+ component: ReleaseNotes,
71
+ },
72
+ {
73
+ path: '/edit/:course',
74
+ props: true,
75
+ component: CourseEditor,
76
+ },
77
+ {
78
+ path: '/study',
79
+ name: 'study',
80
+ component: Study,
81
+ },
82
+ {
83
+ path: '/study/:focusCourseID',
84
+ component: Study,
85
+ props: true,
86
+ },
87
+ {
88
+ path: '/random',
89
+ name: 'random',
90
+ alias: ['/r'],
91
+ props: {
92
+ randomPreview: true,
93
+ },
94
+ component: Study,
95
+ },
96
+ {
97
+ path: '/classrooms',
98
+ name: 'classrooms',
99
+ component: Classrooms,
100
+ },
101
+ {
102
+ path: '/classrooms/:classroomId',
103
+ props: true,
104
+ alias: '/c/:classroomId',
105
+ component: ClassroomCtrlPanel,
106
+ },
107
+ {
108
+ path: '/classrooms/:classroomId/code',
109
+ props: true,
110
+ alias: '/c/:classroomId',
111
+ component: JoinCode,
112
+ },
113
+ {
114
+ path: '/courses',
115
+ alias: ['/quilts', '/q'],
116
+ component: Courses,
117
+ },
118
+ {
119
+ path: '/courses/:query',
120
+ props: true,
121
+ alias: ['/quilts/:query', '/q/:query'],
122
+ component: CourseRouter,
123
+ },
124
+ {
125
+ path: '/courses/:courseId/elo',
126
+ props: true,
127
+ alias: ['/quilts/:courseId/elo', '/q/:courseId/elo'],
128
+ component: ELOModerator,
129
+ },
130
+ {
131
+ path: '/courses/:courseId/tags/:tagId',
132
+ props: true,
133
+ alias: ['/quilts/:courseId/tags/:tagId', '/q/:courseId/tags/:tagId'],
134
+ component: TagInformation,
135
+ },
136
+ {
137
+ path: '/courses/:previewCourseID/preview',
138
+ props: true,
139
+ alias: ['/quilts/:previewCourseID/preview', '/q/:previewCourseID/preview'],
140
+ component: Study,
141
+ },
142
+ {
143
+ path: '/admin',
144
+ component: Admin,
145
+ },
146
+ {
147
+ path: '/user/:username',
148
+ alias: '/u/:username',
149
+ props: true,
150
+ component: User,
151
+ children: [
152
+ {
153
+ path: 'new',
154
+ component: User,
155
+ }, //,
156
+ // {
157
+ // path: '/stats',
158
+ // component: Stats,
159
+ // },
160
+ ],
161
+ },
162
+ {
163
+ path: '/user/:_id/stats',
164
+ props: true,
165
+ alias: ['/u/:_id/stats'],
166
+ component: Stats,
167
+ },
168
+ ],
169
+ });
170
+
171
+ router.beforeEach((to, from, next) => {
172
+ // paths that should be handled by the server, not the SPA
173
+ const apiPaths = ['/express', '/couch'];
174
+
175
+ if (apiPaths.some((path) => to.path.startsWith(path))) {
176
+ // Return false to cancel navigation and let the browser handle the request
177
+ return false;
178
+ }
179
+
180
+ // Continue with navigation for all other routes
181
+ next();
182
+ });
183
+
184
+ export default router;
@@ -0,0 +1,192 @@
1
+ import { vi, describe, test, expect, beforeEach } from 'vitest';
2
+ import serverRequest from './index';
3
+ import { ServerRequestType, Status, CreateClassroom } from '@vue-skuilder/common';
4
+
5
+ // Instead of extending ServerRequest, directly use the CreateClassroom type
6
+ describe('serverRequest', () => {
7
+ let mockXHR: {
8
+ open: ReturnType<typeof vi.fn>;
9
+ send: ReturnType<typeof vi.fn>;
10
+ setRequestHeader: ReturnType<typeof vi.fn>;
11
+ withCredentials: boolean;
12
+ timeout: number;
13
+ onload?: () => void;
14
+ ontimeout?: () => void;
15
+ onerror?: () => void;
16
+ readyState?: number;
17
+ status?: number;
18
+ responseText?: string;
19
+ };
20
+
21
+ // Create a base test request that matches CreateClassroom exactly
22
+ const baseTestRequest: CreateClassroom = {
23
+ type: ServerRequestType.CREATE_CLASSROOM,
24
+ user: 'testuser',
25
+ data: {
26
+ students: [],
27
+ teachers: ['testuser'],
28
+ name: 'Test Classroom',
29
+ classMeetingSchedule: 'Never',
30
+ peerAssist: false,
31
+ joinCode: 'TEST123',
32
+ },
33
+ response: null,
34
+ };
35
+
36
+ beforeEach(() => {
37
+ mockXHR = {
38
+ open: vi.fn(),
39
+ send: vi.fn(),
40
+ setRequestHeader: vi.fn(),
41
+ withCredentials: false,
42
+ timeout: 0,
43
+ };
44
+
45
+ // eslint-disable-next-line
46
+ global.XMLHttpRequest = vi.fn(() => mockXHR) as any;
47
+ });
48
+
49
+ test('configures XMLHttpRequest correctly', async () => {
50
+ // Create a valid request with a timeout
51
+ const testRequest: CreateClassroom = {
52
+ ...baseTestRequest,
53
+ timeout: 7000,
54
+ };
55
+
56
+ // Start the request
57
+ const requestPromise = serverRequest(testRequest);
58
+
59
+ // Check that XMLHttpRequest was configured correctly
60
+ expect(mockXHR.open).toHaveBeenCalledWith('POST', expect.any(String), true);
61
+ expect(mockXHR.withCredentials).toBe(true);
62
+ expect(mockXHR.setRequestHeader).toHaveBeenCalledWith('Content-Type', 'application/json');
63
+ expect(mockXHR.timeout).toBe(7000);
64
+ expect(mockXHR.send).toHaveBeenCalledWith(JSON.stringify(testRequest));
65
+
66
+ // Simulate successful response with the expected format for CreateClassroom
67
+ mockXHR.responseText = JSON.stringify({
68
+ status: Status.ok,
69
+ ok: true,
70
+ joincode: 'ABC123',
71
+ uuid: '123-456-789',
72
+ });
73
+ if (mockXHR.onload) mockXHR.onload();
74
+
75
+ // Wait for the request to complete
76
+ const result = await requestPromise;
77
+
78
+ // Verify the result matches the expected format
79
+ expect(result.response).toEqual({
80
+ status: Status.ok,
81
+ ok: true,
82
+ joincode: 'ABC123',
83
+ uuid: '123-456-789',
84
+ });
85
+ });
86
+
87
+ test('handles successful response', async () => {
88
+ // Create a promise that will complete when onload is triggered
89
+ const requestPromise = serverRequest(baseTestRequest);
90
+
91
+ // Simulate a successful response that matches the expected structure
92
+ mockXHR.responseText = JSON.stringify({
93
+ status: Status.ok,
94
+ ok: true,
95
+ joincode: 'TEST123',
96
+ uuid: '123-456',
97
+ });
98
+ if (mockXHR.onload) mockXHR.onload();
99
+
100
+ // Wait for the request to complete
101
+ const result = await requestPromise;
102
+
103
+ // Verify the response was processed correctly
104
+ expect(result.response).toEqual({
105
+ status: Status.ok,
106
+ ok: true,
107
+ joincode: 'TEST123',
108
+ uuid: '123-456',
109
+ });
110
+ });
111
+
112
+ test('handles JSON parse error in response', async () => {
113
+ // Create a promise that will complete when onload is triggered
114
+ const requestPromise = serverRequest(baseTestRequest);
115
+
116
+ // Simulate an invalid JSON response
117
+ mockXHR.responseText = 'Not valid JSON';
118
+ if (mockXHR.onload) mockXHR.onload();
119
+
120
+ // Wait for the request to complete
121
+ const result = await requestPromise;
122
+
123
+ // Verify error handling
124
+ expect(result.response).toEqual({
125
+ status: Status.error,
126
+ ok: false,
127
+ errorText: expect.stringContaining('Failed to parse response'),
128
+ });
129
+ });
130
+
131
+ test('handles request timeout', async () => {
132
+ // Create a request with custom timeout
133
+ const testRequest: CreateClassroom = {
134
+ ...baseTestRequest,
135
+ timeout: 5000,
136
+ };
137
+
138
+ // Create a promise
139
+ const requestPromise = serverRequest(testRequest);
140
+
141
+ // Verify timeout is set correctly
142
+ expect(mockXHR.timeout).toBe(5000);
143
+
144
+ // Simulate timeout
145
+ if (mockXHR.ontimeout) mockXHR.ontimeout();
146
+
147
+ // Wait for the request to complete
148
+ const result = await requestPromise;
149
+
150
+ // Verify timeout handling
151
+ expect(result.response).toEqual({
152
+ status: Status.error,
153
+ ok: false,
154
+ errorText: 'Request timed out',
155
+ });
156
+ });
157
+
158
+ test('handles network error', async () => {
159
+ // Create a request
160
+ const requestPromise = serverRequest(baseTestRequest);
161
+
162
+ // Simulate network error
163
+ if (mockXHR.onerror) mockXHR.onerror();
164
+
165
+ // Wait for the request to complete
166
+ const result = await requestPromise;
167
+
168
+ // Verify error handling
169
+ expect(result.response).toEqual({
170
+ status: Status.error,
171
+ ok: false,
172
+ errorText: 'Network error occurred',
173
+ });
174
+ });
175
+
176
+ test('handles exception during request setup', async () => {
177
+ // Make XMLHttpRequest.open throw an error
178
+ mockXHR.open = vi.fn().mockImplementation(() => {
179
+ throw new Error('Connection refused');
180
+ });
181
+
182
+ // Make the request which should catch the error
183
+ const result = await serverRequest(baseTestRequest);
184
+
185
+ // Verify error is caught and handled
186
+ expect(result.response).toEqual({
187
+ status: Status.error,
188
+ ok: false,
189
+ errorText: 'Connection refused',
190
+ });
191
+ });
192
+ });
@@ -0,0 +1,71 @@
1
+ import { Status } from '@vue-skuilder/common';
2
+ import ENV from '@/ENVIRONMENT_VARS';
3
+ import { ServerRequest } from '@vue-skuilder/common';
4
+
5
+ const SERVER = ENV.EXPRESS_SERVER_PROTOCOL + '://' + ENV.EXPRESS_SERVER_URL;
6
+
7
+ /**
8
+ * Makes an authenticated request to the express backend and returns the response.
9
+
10
+ * @param requestData
11
+ * @returns
12
+ */
13
+ export default async function serverRequest<T extends ServerRequest>(requestData: T): Promise<T> {
14
+ return new Promise<T>((resolve) => {
15
+ try {
16
+ const xml = new XMLHttpRequest();
17
+ xml.withCredentials = true;
18
+ xml.open('POST', SERVER, true);
19
+ xml.setRequestHeader('Content-Type', 'application/json');
20
+ xml.timeout = requestData.timeout || 7000;
21
+
22
+ // Handle the response when it completes
23
+ xml.onload = function () {
24
+ try {
25
+ requestData.response = JSON.parse(xml.responseText);
26
+ resolve(requestData);
27
+ } catch (parseError) {
28
+ requestData.response = {
29
+ status: Status.error,
30
+ ok: false,
31
+ errorText: `Failed to parse response: ${
32
+ parseError instanceof Error ? parseError.message : JSON.stringify(parseError)
33
+ }`,
34
+ };
35
+ resolve(requestData);
36
+ }
37
+ };
38
+
39
+ // Handle network errors
40
+ xml.onerror = function () {
41
+ requestData.response = {
42
+ status: Status.error,
43
+ ok: false,
44
+ errorText: 'Network error occurred',
45
+ };
46
+ resolve(requestData);
47
+ };
48
+
49
+ // Handle timeouts
50
+ xml.ontimeout = function () {
51
+ requestData.response = {
52
+ status: Status.error,
53
+ ok: false,
54
+ errorText: 'Request timed out',
55
+ };
56
+ resolve(requestData);
57
+ };
58
+
59
+ // Send the request
60
+ xml.send(JSON.stringify(requestData));
61
+ } catch (error) {
62
+ // Handle any errors that occur during setup
63
+ requestData.response = {
64
+ status: Status.error,
65
+ ok: false,
66
+ errorText: error instanceof Error ? error.message : JSON.stringify(error),
67
+ };
68
+ resolve(requestData);
69
+ }
70
+ });
71
+ }
@@ -0,0 +1,5 @@
1
+ declare module '*.vue' {
2
+ import type { DefineComponent } from 'vue';
3
+ const component: DefineComponent<unknown, unknown, unknown>;
4
+ export default component;
5
+ }
@@ -0,0 +1,122 @@
1
+ // // src/mock/store.ts
2
+
3
+ // import Vue from 'vue';
4
+ // import { DataShape } from '@/base-course/Interfaces/DataShape';
5
+ // import { ViewData } from '@/base-course/Interfaces/ViewData';
6
+ // import { CourseConfig } from '@/server/types';
7
+ // import { FieldInputInstance } from '@/components/Edit/ViewableDataInputForm/FieldInput.types';
8
+ // import { User } from '@vue-skuilder/db';
9
+
10
+ // export const GuestUsername: string = 'Guest';
11
+
12
+ // interface DataInputForm {
13
+ // dataShape: DataShape | null;
14
+ // course: CourseConfig | null;
15
+ // existingData: ViewData[];
16
+ // shapeViews: any[];
17
+ // fields: FieldInputInstance[];
18
+ // localStore: any;
19
+ // uploading: boolean;
20
+ // }
21
+
22
+ // export interface UserConfig {
23
+ // darkMode: boolean;
24
+ // likesConfetti: boolean;
25
+ // }
26
+
27
+ // export interface AppState {
28
+ // _user?: User;
29
+ // userLoginAndRegistrationContainer: {
30
+ // init: boolean;
31
+ // loggedIn: boolean;
32
+ // regDialogOpen: boolean;
33
+ // loginDialogOpen: boolean;
34
+ // };
35
+ // cardPreviewMode: boolean;
36
+ // dataInputForm: DataInputForm;
37
+ // views: {
38
+ // study: {
39
+ // inSession: boolean;
40
+ // courseList: string[];
41
+ // sessionTimeLimit: number;
42
+ // };
43
+ // };
44
+ // config: UserConfig;
45
+ // onLoadComplete: boolean;
46
+ // }
47
+
48
+ // export const defaultState: AppState = {
49
+ // _user: undefined,
50
+ // userLoginAndRegistrationContainer: {
51
+ // init: false,
52
+ // loggedIn: false,
53
+ // regDialogOpen: false,
54
+ // loginDialogOpen: false,
55
+ // },
56
+ // cardPreviewMode: false,
57
+ // dataInputForm: {
58
+ // course: null,
59
+ // dataShape: null,
60
+ // existingData: [],
61
+ // fields: [],
62
+ // localStore: {},
63
+ // shapeViews: [],
64
+ // uploading: false,
65
+ // },
66
+ // views: {
67
+ // study: {
68
+ // inSession: false,
69
+ // courseList: [],
70
+ // sessionTimeLimit: 5,
71
+ // },
72
+ // },
73
+ // config: {
74
+ // darkMode: false,
75
+ // likesConfetti: false,
76
+ // },
77
+ // onLoadComplete: false,
78
+ // };
79
+
80
+ // const Store = new Vuex.Store<AppState>({
81
+ // state: defaultState,
82
+ // mutations: {
83
+ // setUser(state, user: User) {
84
+ // state._user = user;
85
+ // },
86
+ // setLoggedIn(state, loggedIn: boolean) {
87
+ // state.userLoginAndRegistrationContainer.loggedIn = loggedIn;
88
+ // },
89
+ // setConfig(state, config: UserConfig) {
90
+ // state.config = config;
91
+ // },
92
+ // setOnLoadComplete(state, complete: boolean) {
93
+ // state.onLoadComplete = complete;
94
+ // },
95
+ // },
96
+ // actions: {
97
+ // async checkAuth({ commit }) {
98
+ // // Simulate auth check
99
+ // const isLoggedIn = Math.random() > 0.5; // 50% chance of being logged in
100
+ // if (isLoggedIn) {
101
+ // const mockUser = { username: 'MockUser' } as User;
102
+ // commit('setUser', mockUser);
103
+ // commit('setLoggedIn', true);
104
+ // commit('setConfig', { darkMode: false, likesConfetti: true });
105
+ // } else {
106
+ // const guestUser = { username: GuestUsername } as User;
107
+ // commit('setUser', guestUser);
108
+ // commit('setLoggedIn', false);
109
+ // }
110
+ // commit('setOnLoadComplete', true);
111
+ // },
112
+ // },
113
+ // });
114
+
115
+ // export default Store;
116
+
117
+ // export function setDefaultState() {
118
+ // Store.state.config = defaultState.config;
119
+ // }
120
+
121
+ // // Simulate checking auth on load
122
+ // Store.dispatch('checkAuth');