diff --git a/src/JobsJobsJobs/App/package-lock.json b/src/JobsJobsJobs/App/package-lock.json index c10dd26..9ba7992 100644 --- a/src/JobsJobsJobs/App/package-lock.json +++ b/src/JobsJobsJobs/App/package-lock.json @@ -2589,6 +2589,22 @@ "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", "dev": true }, + "@vuelidate/core": { + "version": "2.0.0-alpha.22", + "resolved": "https://registry.npmjs.org/@vuelidate/core/-/core-2.0.0-alpha.22.tgz", + "integrity": "sha512-HqRWY2c5pW6kxHNCupYyQn1+frjiFjEN6qgP0AwByvSu/JdKHDWlWqC2gJoxPiT3Oy23ulge43jVzHT3UO1r4A==", + "requires": { + "vue-demi": "^0.9.1" + } + }, + "@vuelidate/validators": { + "version": "2.0.0-alpha.19", + "resolved": "https://registry.npmjs.org/@vuelidate/validators/-/validators-2.0.0-alpha.19.tgz", + "integrity": "sha512-5TQxi1Wa6jFPYZ4UIUI8RKR2nqN/yujPxRjUMh5vCOhVXoqXPMfoYdfs5DBtfABhmjj7LTtXrZ78WVMQkL9tNw==", + "requires": { + "vue-demi": "^0.9.1" + } + }, "@webassemblyjs/ast": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", @@ -12853,6 +12869,11 @@ "@vue/shared": "3.1.4" } }, + "vue-demi": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.9.1.tgz", + "integrity": "sha512-7s1lufRD2l369eFWPjgLvhqCRk0XzGWJsQc7K4q+0mZtixyGIvsK1Cg88P4NcaRIEiBuuN4q1NN4SZKFKwQswA==" + }, "vue-eslint-parser": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.8.0.tgz", diff --git a/src/JobsJobsJobs/App/package.json b/src/JobsJobsJobs/App/package.json index 3c8fe17..736e655 100644 --- a/src/JobsJobsJobs/App/package.json +++ b/src/JobsJobsJobs/App/package.json @@ -10,6 +10,8 @@ }, "dependencies": { "@mdi/font": "5.9.55", + "@vuelidate/core": "^2.0.0-alpha.22", + "@vuelidate/validators": "^2.0.0-alpha.19", "bootstrap": "^5.1.0", "core-js": "^3.6.5", "date-fns": "^2.23.0", diff --git a/src/JobsJobsJobs/App/src/api/index.ts b/src/JobsJobsJobs/App/src/api/index.ts index e60afee..a012f14 100644 --- a/src/JobsJobsJobs/App/src/api/index.ts +++ b/src/JobsJobsJobs/App/src/api/index.ts @@ -5,6 +5,7 @@ import { Count, LogOnSuccess, Profile, + ProfileForm, ProfileForView, ProfileSearch, ProfileSearchResult, @@ -28,13 +29,22 @@ const apiUrl = (url : string) : string => `http://localhost:5000/api/${url}` * @param user The currently logged-on user * @returns RequestInit parameters */ -const reqInit = (method : string, user : LogOnSuccess) : RequestInit => { +// eslint-disable-next-line +const reqInit = (method : string, user : LogOnSuccess, body : any | undefined = undefined) : RequestInit => { const headers = new Headers() headers.append('Authorization', `Bearer ${user.jwt}`) + if (body) { + headers.append('Content-Type', 'application/json') + return { + headers, + method, + cache: 'no-cache', + body: JSON.stringify(body) + } + } return { headers, method - // mode: 'cors' } } @@ -51,6 +61,18 @@ async function apiResult (resp : Response, action : string) : Promise { + if (resp.status === 200) return true + return `Error ${action} - (${resp.status}) ${await resp.text()}` +} + /** * Run an API action that does not return a result * @@ -156,6 +178,15 @@ export default { retreiveForView: async (id : string, user : LogOnSuccess) : Promise => apiResult(await fetch(apiUrl(`profile/view/${id}`), reqInit('GET', user)), 'retrieving profile'), + /** + * Save a user's profile data + * + * @param data The profile data to be saved + * @param user The currently logged-on user + */ + save: async (data : ProfileForm, user : LogOnSuccess) : Promise => + apiSend(await fetch(apiUrl('profile/save'), reqInit('POST', user, data)), 'saving profile'), + /** * Search for profiles using the given parameters * diff --git a/src/JobsJobsJobs/App/src/api/types.ts b/src/JobsJobsJobs/App/src/api/types.ts index 4381049..b07c0d2 100644 --- a/src/JobsJobsJobs/App/src/api/types.ts +++ b/src/JobsJobsJobs/App/src/api/types.ts @@ -78,27 +78,27 @@ export interface Profile { } /** The data required to update a profile */ -export interface ProfileForm { +export class ProfileForm { /** Whether the citizen to whom this profile belongs is actively seeking employment */ - isSeekingEmployment : boolean + isSeekingEmployment = false /** Whether this profile should appear in the public search */ - isPublic : boolean + isPublic = false /** The user's real name */ - realName : string + realName = '' /** The ID of the continent on which the citizen is located */ - continentId : string + continentId = '' /** The area within that continent where the citizen is located */ - region : string + region = '' /** If the citizen is available for remote work */ - remoteWork : boolean + remoteWork = false /** If the citizen is seeking full-time employment */ - fullTime : boolean + fullTime = false /** The user's professional biography */ - biography : string + biography = '' /** The user's past experience */ experience : string | undefined /** The skills for the user */ - skills : Skill[] + skills : Skill[] = [] } /** The data required to show a viewable profile */ diff --git a/src/JobsJobsJobs/App/src/components/MarkdownEditor.vue b/src/JobsJobsJobs/App/src/components/MarkdownEditor.vue index 925e631..fb095a1 100644 --- a/src/JobsJobsJobs/App/src/components/MarkdownEditor.vue +++ b/src/JobsJobsJobs/App/src/components/MarkdownEditor.vue @@ -1,17 +1,16 @@ @@ -35,7 +34,8 @@ export default defineComponent({ label: { type: String, required: true - } + }, + isInvalid: { type: Boolean } }, emits: ['update:text'], setup (props) { diff --git a/src/JobsJobsJobs/App/src/views/citizen/EditProfile.vue b/src/JobsJobsJobs/App/src/views/citizen/EditProfile.vue index 795a2ee..0f9ee69 100644 --- a/src/JobsJobsJobs/App/src/views/citizen/EditProfile.vue +++ b/src/JobsJobsJobs/App/src/views/citizen/EditProfile.vue @@ -3,97 +3,94 @@

Employment Profile

-
-
-
-
- - -
-
Leave blank to use your NAS display name
+ +
+
+ + +
+
Leave blank to use your NAS display name
+
+
+
+ + +
+

+ If you have found employment, consider telling your fellow + citizens about it! +

+
+
+
+ + +
+
Please select a continent
+
+
+
+ +
Please enter a region
+ +
+
Country, state, geographic area, etc.
+
+ +
+
+ +
-
-
-
- - -
-

- If you have found employment, consider telling your fellow - citizens about it! -

+
+
+ +
-
-
-
- - -
-
-
-
- - -
-
Country, state, geographic area, etc.
-
+
+
+

+ Skills   + +

- -
-
-
- - -
-
-
-
- - -
-
-
-
-

- Skills   - -

-
-

Experience

-

- This application does not have a place to individually list your chronological job history; however, you can - use this area to list prior jobs, their dates, and anything else you want to include that’s not - already a part of your Professional Biography above. -

+
+
+

Experience

+

+ This application does not have a place to individually list your chronological job history; however, you can + use this area to list prior jobs, their dates, and anything else you want to include that’s not + already a part of your Professional Biography above. +

+
-
-
-
- - -
+
+
+ +
-
-
- - -
+
+

Please correct the errors above

+ +
@@ -106,13 +103,16 @@