UNCLASSIFIED

Commit e462e481 authored by graham.smith's avatar graham.smith
Browse files

Merge branch 'LB-201' into 'master'

Lb 201: frontend audit for courses and course detail page with scss fixes

See merge request platform-one/products/bullhorn/launchboard-fe!106
parents 61035ec2 0bbd7463
...@@ -99,9 +99,9 @@ ...@@ -99,9 +99,9 @@
"dev": true "dev": true
}, },
"@babel/highlight": { "@babel/highlight": {
"version": "7.12.13", "version": "7.13.10",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz",
"integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.12.11", "@babel/helper-validator-identifier": "^7.12.11",
...@@ -360,9 +360,9 @@ ...@@ -360,9 +360,9 @@
"dev": true "dev": true
}, },
"@babel/highlight": { "@babel/highlight": {
"version": "7.12.13", "version": "7.13.10",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz",
"integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.12.11", "@babel/helper-validator-identifier": "^7.12.11",
...@@ -651,9 +651,9 @@ ...@@ -651,9 +651,9 @@
} }
}, },
"@babel/generator": { "@babel/generator": {
"version": "7.13.0", "version": "7.13.9",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.0.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz",
"integrity": "sha512-zBZfgvBB/ywjx0Rgc2+BwoH/3H+lDtlgD4hBOpEv5LxRnYsm/753iRuLepqnYlynpjC3AdQxtxsoeHJoEEwOAw==", "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.13.0", "@babel/types": "^7.13.0",
...@@ -1367,9 +1367,9 @@ ...@@ -1367,9 +1367,9 @@
"dev": true "dev": true
}, },
"@babel/highlight": { "@babel/highlight": {
"version": "7.12.13", "version": "7.13.10",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz",
"integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.12.11", "@babel/helper-validator-identifier": "^7.12.11",
...@@ -1977,9 +1977,9 @@ ...@@ -1977,9 +1977,9 @@
"dev": true "dev": true
}, },
"@babel/highlight": { "@babel/highlight": {
"version": "7.12.13", "version": "7.13.10",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz",
"integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.12.11", "@babel/helper-validator-identifier": "^7.12.11",
...@@ -1988,9 +1988,9 @@ ...@@ -1988,9 +1988,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.13.4", "version": "7.13.13",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.4.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz",
"integrity": "sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA==", "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==",
"dev": true "dev": true
}, },
"@babel/template": { "@babel/template": {
...@@ -2960,9 +2960,9 @@ ...@@ -2960,9 +2960,9 @@
} }
}, },
"semver": { "semver": {
"version": "7.3.4", "version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"lru-cache": "^6.0.0" "lru-cache": "^6.0.0"
...@@ -6334,9 +6334,9 @@ ...@@ -6334,9 +6334,9 @@
"dev": true "dev": true
}, },
"string-width": { "string-width": {
"version": "4.2.0", "version": "4.2.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
"dev": true, "dev": true,
"requires": { "requires": {
"emoji-regex": "^8.0.0", "emoji-regex": "^8.0.0",
...@@ -7766,9 +7766,9 @@ ...@@ -7766,9 +7766,9 @@
} }
}, },
"is-path-inside": { "is-path-inside": {
"version": "3.0.2", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
"integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
"dev": true "dev": true
}, },
"is-stream": { "is-stream": {
...@@ -8041,9 +8041,9 @@ ...@@ -8041,9 +8041,9 @@
} }
}, },
"rxjs": { "rxjs": {
"version": "6.6.3", "version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^1.9.0"
...@@ -13570,9 +13570,9 @@ ...@@ -13570,9 +13570,9 @@
} }
}, },
"semver": { "semver": {
"version": "7.3.4", "version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"lru-cache": "^6.0.0" "lru-cache": "^6.0.0"
...@@ -19666,6 +19666,12 @@ ...@@ -19666,6 +19666,12 @@
"yargs-parser": "10.x" "yargs-parser": "10.x"
}, },
"dependencies": { "dependencies": {
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"yargs-parser": { "yargs-parser": {
"version": "18.1.3", "version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
...@@ -19674,14 +19680,6 @@ ...@@ -19674,14 +19680,6 @@
"requires": { "requires": {
"camelcase": "^5.0.0", "camelcase": "^5.0.0",
"decamelize": "^1.2.0" "decamelize": "^1.2.0"
},
"dependencies": {
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
}
} }
} }
} }
......
...@@ -123,11 +123,6 @@ export default { ...@@ -123,11 +123,6 @@ export default {
} }
} }
.v-btn:not(.v-btn--outlined).primary {
color: $button-text-color;
border: $button-border;
}
// fade-in animation // fade-in animation
.v-application--wrap { .v-application--wrap {
animation: fade-in 3s forwards; animation: fade-in 3s forwards;
......
...@@ -68,9 +68,10 @@ export default { ...@@ -68,9 +68,10 @@ export default {
window.open("/api/courses/export"); window.open("/api/courses/export");
}, },
async getCourseRegistrationsById(courseId, params) { async getCourseRegistrationsById(courseId, params) {
return await HTTP.get(`/courses/${courseId}/registrations`, { const response = await HTTP.get(`/courses/${courseId}/registrations`, {
params, params,
}); });
return response;
}, },
async setUserAttendance(courseId, body) { async setUserAttendance(courseId, body) {
return await HTTP.put( return await HTTP.put(
......
...@@ -57,15 +57,12 @@ ...@@ -57,15 +57,12 @@
Cancel Cancel
</v-btn> </v-btn>
<v-btn <v-btn
:disabled="!isCourseSelected" :disabled="
!isCourseSelected ||
!internalSelectedMembers.length ||
areNoAvailableSeats
"
color="primary" color="primary"
class="limegreen"
:class="{
'not-operable':
!isCourseSelected ||
!internalSelectedMembers.length ||
areNoAvailableSeats,
}"
:loading="state.isAddingBusy" :loading="state.isAddingBusy"
text text
@click="addSelectedUsersToSelectedCourses()" @click="addSelectedUsersToSelectedCourses()"
......
...@@ -167,9 +167,7 @@ export default { ...@@ -167,9 +167,7 @@ export default {
.mt-n5px { .mt-n5px {
margin-top: -5px; margin-top: -5px;
} }
.theme--dark.v-text-field.no-border .theme--dark.v-text-field > .v-input__control > .v-input__slot:before {
> .v-input__control
> .v-input__slot:before {
border-color: transparent !important; border-color: transparent !important;
display: none; display: none;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</div> </div>
<v-spacer class="d-none d-sm-flex" /> <v-spacer class="d-none d-sm-flex" />
<v-btn <v-btn
color="secondary" color="primary"
href="https://jira.il2.dso.mil/servicedesk/customer/portal/1" href="https://jira.il2.dso.mil/servicedesk/customer/portal/1"
target="_blank" target="_blank"
class="mx-auto no-link" class="mx-auto no-link"
...@@ -26,8 +26,7 @@ ...@@ -26,8 +26,7 @@
</div> </div>
<v-spacer /> <v-spacer />
<v-btn <v-btn
outlined color="tertiary"
color="secondary"
href="mailto:help@dso.mil" href="mailto:help@dso.mil"
target="_blank" target="_blank"
class="mx-auto" class="mx-auto"
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<v-btn <v-btn
icon icon
color="secondary" color="secondary"
class="no-border no-shadow no-link" class="no-link"
v-bind="attrs" v-bind="attrs"
v-on="on" v-on="on"
href="https://login.dso.mil/auth/realms/baby-yoda/account/" href="https://login.dso.mil/auth/realms/baby-yoda/account/"
......
...@@ -41,12 +41,7 @@ ...@@ -41,12 +41,7 @@
</router-link> </router-link>
</div> </div>
</v-toolbar-items> </v-toolbar-items>
<v-btn <v-btn icon class="no-link nav-item" id="settings-button" to="/settings">
icon
class="no-shadow no-border no-link nav-item"
id="settings-button"
to="/settings"
>
<v-icon>mdi-cog</v-icon> <v-icon>mdi-cog</v-icon>
</v-btn> </v-btn>
<v-app-bar-nav-icon <v-app-bar-nav-icon
......
...@@ -35,7 +35,8 @@ ...@@ -35,7 +35,8 @@
<v-btn <v-btn
@click="removePersonnel" @click="removePersonnel"
:disabled="personnel.selectedPersonnel.length === 0" :disabled="personnel.selectedPersonnel.length === 0"
class="mr-3 table-action-btn" class="mr-3"
color="accent"
> >
<v-icon class="mr-2">mdi-trash-can</v-icon> <v-icon class="mr-2">mdi-trash-can</v-icon>
Remove Selected Remove Selected
...@@ -43,7 +44,8 @@ ...@@ -43,7 +44,8 @@
<v-btn <v-btn
@click="sendEmailToPersonnel" @click="sendEmailToPersonnel"
:disabled="personnel.selectedPersonnel.length === 0" :disabled="personnel.selectedPersonnel.length === 0"
class="mr-3 table-action-btn" class="mr-3"
color="accent"
> >
<v-icon class="mr-2">mdi-pencil</v-icon> <v-icon class="mr-2">mdi-pencil</v-icon>
Email Selected Email Selected
......
...@@ -61,12 +61,7 @@ ...@@ -61,12 +61,7 @@
<!-- dots menu visible in xs --> <!-- dots menu visible in xs -->
<v-menu left content-class="project-summary-menu"> <v-menu left content-class="project-summary-menu">
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn <v-btn icon v-bind="attrs" v-on="on" class="d-sm-none">
icon
v-bind="attrs"
v-on="on"
class="d-sm-none no-border no-shadow"
>
<v-icon>mdi-dots-vertical</v-icon> <v-icon>mdi-dots-vertical</v-icon>
</v-btn> </v-btn>
</template> </template>
...@@ -136,7 +131,6 @@ ...@@ -136,7 +131,6 @@
v-on="on" v-on="on"
@click.native.stop @click.native.stop
color="secondary" color="secondary"
class="no-border no-shadow"
> >
<v-icon small>$vuetify.icons.gitlab</v-icon> <v-icon small>$vuetify.icons.gitlab</v-icon>
</v-btn> </v-btn>
...@@ -154,7 +148,6 @@ ...@@ -154,7 +148,6 @@
v-on="on" v-on="on"
@click.native.stop @click.native.stop
color="secondary" color="secondary"
class="no-border no-shadow"
> >
<GitLabIcon class="icon small" icon="rocket" /> <GitLabIcon class="icon small" icon="rocket" />
</v-btn> </v-btn>
...@@ -172,7 +165,6 @@ ...@@ -172,7 +165,6 @@
v-on="on" v-on="on"
@click.native.stop @click.native.stop
color="secondary" color="secondary"
class="no-border no-shadow"
> >
<v-icon small>$vuetify.icons.jira</v-icon> <v-icon small>$vuetify.icons.jira</v-icon>
</v-btn> </v-btn>
...@@ -190,7 +182,6 @@ ...@@ -190,7 +182,6 @@
v-on="on" v-on="on"
@click.native.stop @click.native.stop
color="secondary" color="secondary"
class="no-border no-shadow"
> >
<v-icon small>$vuetify.icons.confluence</v-icon> <v-icon small>$vuetify.icons.confluence</v-icon>
</v-btn> </v-btn>
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
<v-spacer /> <v-spacer />
<slot name="header-right"></slot> <slot name="header-right"></slot>
<v-btn <v-btn
class="no-shadow no-border"
v-if="!hideCollapse && !hideCollapseButton" v-if="!hideCollapse && !hideCollapseButton"
icon icon
@click="isCollapsed = !isCollapsed" @click="isCollapsed = !isCollapsed"
......
<template> <template>
<div> <v-container>
<div <v-row>
class="d-flex flex-wrap flex-sm-nowrap px-2 px-sm-4 mb-4 justify-space-between" <v-col>
> <h2 class="text-left px-0 my-0">Students</h2>
<div class="text-left"> </v-col>
<h2 class="px-0 mb-2 subhead">Students</h2> </v-row>
</div> <v-row class="filter-wrapper filter-input mb-4">
</div> <v-col cols="12" sm="6" md="3">
<v-text-field
v-model="search"
ref="filterSearch"
append-icon="mdi-magnify"
@keyup="fetchDebounced"
@click:append="setInputElementFocus($refs.filterSearch)"
placeholder="Search"
single-line
hide-details
></v-text-field>
</v-col>
</v-row>
<v-data-table <v-data-table
v-if="headers" v-if="headers"
v-model="selectedUsers" v-model="selectedUsers"
:headers="headers" :headers="headers"
:items="listItems" :items="listItems"
:search="search"
show-select show-select
mobile-breakpoint="800" mobile-breakpoint="800"
:options.sync="options" :options.sync="options"
...@@ -85,11 +98,12 @@ ...@@ -85,11 +98,12 @@
<span v-bind:key="h.value" v-else>{{ h.text }}</span> <span v-bind:key="h.value" v-else>{{ h.text }}</span>
</template> </template>
</v-data-table> </v-data-table>
<div class="d-flex flex-wrap mt-5 table-action-btn"> <div class="d-flex flex-wrap mt-5">
<v-btn <v-btn
@click="removeSelectedStudent" @click="removeSelectedStudent"
:disabled="selectedUsers.length === 0" :disabled="selectedUsers.length === 0"
class="mr-3 table-action-btn" class="mr-3"
color="accent"
> >
<v-icon class="mr-2">mdi-trash-can</v-icon> <v-icon class="mr-2">mdi-trash-can</v-icon>
Remove Selected Remove Selected
...@@ -97,76 +111,14 @@ ...@@ -97,76 +111,14 @@
<v-btn <v-btn
@click="sendEmailToStudents" @click="sendEmailToStudents"
:disabled="selectedUsers.length === 0" :disabled="selectedUsers.length === 0"
class="mr-3 table-action-btn" class="mr-3"
color="accent"
> >
<v-icon class="mr-2">mdi-pencil</v-icon> <v-icon class="mr-2">mdi-pencil</v-icon>
Email Selected Email Selected
</v-btn> </v-btn>
<div class="d-flex flex-column mr-n4 mt-n1 ml-auto">
<v-btn
text
color="secondary"
class="no-border no-shadow"
@click="state.isAddingStudent = true"
>
<v-icon class="mr-2">mdi-plus-circle</v-icon>
<h4 class="px-0 ma-0">Add Student</h4>
</v-btn>
</div>
</div> </div>
<v-dialog </v-container>
v-model="state.isAddingStudent"
persistent
no-click-animation
max-width="500px"
>
<v-card>
<v-card-title>
<span class="headline"
>Add new student to {{ currentTrainingCourse.name }}</span
>
</v-card-title>
<v-card-text>
<UserSelect
ref="userSelect"
v-model="studentToAdd"
:rules="[
inputRules.required,
inputRules.duplicates(
studentToAdd,
currentTrainingCourse.students,
'User is already a student of this training'
),
]"
multiple
required
/>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color=""
:disabled="state.isAddingBusy"
text
@click="cancelAddStudent()"
>
Cancel
</v-btn>
<v-btn
:disabled="state.isAddingDuplicate || !studentToAdd"
color="primary"
:loading="state.isAddingBusy"
text
@click="addStudent()"
>
Add Student
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template> </template>
<script> <script>
...@@ -182,21 +134,24 @@ import { ...@@ -182,21 +134,24 @@ import {
} from "@/config/table-constants"; } from "@/config/table-constants";
import { createDefaultPaginationParams } from "@/utils/tableHelpers"; import { createDefaultPaginationParams } from "@/utils/tableHelpers";
import moment from "moment"; import moment from "moment";
import UserSelect from "@/components/UserSelect";
import { minimumWait } from "@/utils/timing"; import { minimumWait } from "@/utils/timing";
const minCheckBoxWaitTime = 500; // ms const minCheckBoxWaitTime = 500; // ms
export default { export default {
name: "TrainingAttendance", name: "TrainingAttendance",
components: { UserSelect },
props: { props: {
trainingCourse: { trainingCourse: {
type: Object, type: Object,
required: true, required: true,
}, },
reload: {
type: Number,
},
}, },
data() { data() {
return { return {
search: "",
darkMode: null,
inputRules, inputRules,
loading: false, loading: false,
total: 0, total: 0,
...@@ -217,6 +172,7 @@ export default { ...@@ -217,6 +172,7 @@ export default {
}; };
}, },
async mounted() { async mounted() {
this.darkMode = this.$vuetify.theme.dark;
await this.fetchData(); await this.fetchData();
}, },
methods: { methods: {
...@@ -234,9 +190,8 @@ export default { ...@@ -234,9 +190,8 @@ export default {
try { try {
const response = await TrainingService.getCourseRegistrationsById( const response = await TrainingService.getCourseRegistrationsById(
this.currentCourseId, this.currentCourseId,
{ ...this.params, attendance: true } { ...this.params, attendance: true, q: this.search }
); );
this.listItems = this.listItems =
response.registrations?.map((item) => { response.registrations?.map((item) => {
item.completed = { value: item.completed, loading: false }; item.completed = { value: item.completed, loading: false };
...@@ -345,33 +300,6 @@ export default { ...@@ -345,33 +300,6 @@ export default {
await minimumWait(startTime, minCheckBoxWaitTime); await minimumWait(startTime, minCheckBoxWaitTime);
item.completed.loading = false; item.completed.loading = false;
}, },
async addStudent(student) {
if (!student) {
student = this.studentToAdd;
}
this.state.isAddingBusy = true;
try {
await TrainingService.addStudents(
this.currentTrainingCourse.id,
student
);
this.studentToAdd = student;
} catch (error) {
const errorMessage = error;
this.$store.commit(SET_ERROR_MESSAGE, errorMessage);
} finally {
await this.fetchDebounced();
this.state.isAddingBusy = false;
this.state.isAddingStudent = false;
this.$refs.userSelect && this.$refs.userSelect.clear();
}
},
cancelAddStudent() {
this.studentToAdd = null;
this.state.isAddingStudent = false;
this.state.isAddingDuplicate = false;
this.$refs.userSelect && this.$refs.userSelect.clear();
},
dateIsValid(date) { dateIsValid(date) {
return moment(date, "YYYY-MM-DD").isValid(); return moment(date, "YYYY-MM-DD").isValid();
}, },
...@@ -380,6 +308,12 @@ export default { ...@@ -380,6 +308,12 @@ export default {
}, },
}, },
watch: { watch: {
reload: function (newVal, oldVal) {
if (isEqual(oldVal, newVal)) {
return;
}
this.fetchDebounced();
},
options: { options: {
handler(newOptions, prevOptions) { handler(newOptions, prevOptions) {
// reduce unnecessary api calls // reduce unnecessary api calls
...@@ -450,3 +384,8 @@ export default { ...@@ -450,3 +384,8 @@ export default {
}, },
}; };
</script> </script>
<style lang="scss">
.search {
width: 250px;
}
</style>
...@@ -68,7 +68,8 @@ export default new Vuetify({ ...@@ -68,7 +68,8 @@ export default new Vuetify({
dark: { dark: {
primary: "#BDC931", primary: "#BDC931",
secondary: "#ffffff", secondary: "#ffffff",
accent: "#FA8022", tertiary: "#031322",
accent: "#272727",
success: "#4CAF50", success: "#4CAF50",
info: "#2196F3", info: "#2196F3",
warning: "#FB8C00", warning: "#FB8C00",
...@@ -77,7 +78,8 @@ export default new Vuetify({ ...@@ -77,7 +78,8 @@ export default new Vuetify({
light: { light: {
primary: "#BDC931", primary: "#BDC931",
secondary: "#031321", secondary: "#031321",
accent: "#82B1FF", tertiary: "#ffffff",
accent: "#272727",
error: "#FF5252", error: "#FF5252",
info: "#2196F3", info: "#2196F3",
success: "#4CAF50", success: "#4CAF50",
......
...@@ -65,10 +65,15 @@ body { ...@@ -65,10 +65,15 @@ body {
.v-btn { .v-btn {
height: 40px; height: 40px;
text-transform: uppercase; text-transform: uppercase;
border: none !important;
&:not(.v-btn--round).v-size--default { &:not(.v-btn--round).v-size--default {
min-width: 160px; min-width: 160px;
} }
&.primary {
color: $primary-button-text-color !important;
}
} }
// some text areas have a label too close to the text field // some text areas have a label too close to the text field
...@@ -167,59 +172,68 @@ body { ...@@ -167,59 +172,68 @@ body {
} }
} }
.v-btn.no-shadow { .filter-input {
box-shadow: none !important; .v-input {
} input,
.v-btn.no-border { .v-select__selections {
border: none !important; padding-left: 8px;
} color: #000000;
.v-btn:disabled { }
h1, .v-input__control {
h2, padding-right: 8px;
h3, }
h4 {
color: rgba(255, 255, 255, 0.3) !important;
} }
}
.table-no-link { .v-icon {
color: #12b5f6; color: rgba(0, 0, 0, 0.54) !important;
&:hover {
color: lighten(#12b5f6, 10%) !important;
} }
}
.theme--dark { .v-text-field {
button { padding-top: 0;
&.dark-btn { background: white;
background: $p1-light-green !important; border-radius: 5px !important;
color: black !important;
span.v-btn__content { color: $p1-light-green;
color: black !important;
}
}
&.light-btn {
background: white !important;
color: black !important;
span.v-btn__content { .v-input__slot::before,
color: black !important; .v-input__control::before {
} /* don't display the line unless input is active */
display: none;
} }
} }
.v-data-table a:hover { input::placeholder {
text-decoration: underline; color: black !important;
} }
}
.theme--dark {
a.v-btn.secondary { a.v-btn.secondary {
span { span {
color: black; color: black;
} }
} }
.v-btn {
/* secondary buttons in dark mode are light, so their text needs to be the secondary-text-color */
&.secondary {
color: map-get($material-dark, "secondary-text-color");
}
/* tertiary buttons in dark mode are dark, so their text needs to match the default text color */
&.tertiary {
border: 1px solid map-get($material-dark, "text-color") !important;
}
&.no-link.v-btn--active {
&::before {
opacity: 0.08;
}
&:not(:hover)::before {
opacity: 0;
}
}
}
h1, h1,
h2, h2,
h3, h3,
...@@ -234,59 +248,6 @@ body { ...@@ -234,59 +248,6 @@ body {
margin-top: 65px; margin-top: 65px;
margin-bottom: 60px; margin-bottom: 60px;
} }
.filter-search {
div {
padding: 0;
&::before {
border-color: unset !important;
}
}
label {
/* design does not have a label or placeholder
for the search bar */
display: none;
}
/* no underline when active */
.v-text-field > .v-input__control > .v-input__slot:after {
width: 0 !important;
}
.v-text-field {
margin-top: -7px;
background: white;
border-radius: 5px !important;
color: $p1-light-green;
max-width: 250px;
.v-input__slot::before,
.v-input__control::before {
width: 97%;
left: 3px;
/* don't display the line unless input is active */
display: none;
}
input {
color: black;
padding-left: 5px;
}
label {
color: black;
padding-left: 10px;
}
.v-icon {
color: black;
padding-right: 10px;
}
}
}
// make scrollbar color light for menus // make scrollbar color light for menus
.v-menu__content { .v-menu__content {
background-color: #000000; background-color: #000000;
...@@ -306,9 +267,11 @@ body { ...@@ -306,9 +267,11 @@ body {
font-size: 20px; font-size: 20px;
} }
a.link-to-team { a:not(.v-btn--icon) {
text-transform: capitalize; &.column-link-highlight,
color: $p1-light-green !important; &:hover {
color: var(--v-primary-base) !important;
}
} }
.v-data-table-header th { .v-data-table-header th {
...@@ -342,40 +305,6 @@ body { ...@@ -342,40 +305,6 @@ body {
} }
} }
.v-btn {
&.primary {
background-color: white !important;
border-color: white !important;
color: black !important;
}
&.tertiary {
background: transparent !important;
border: thin solid white !important;
color: white !important;
}
&.v-btn--outlined.secondary--text {
border-color: #e9e9e9;
}
&.no-link.v-btn--active {
&::before {
opacity: 0.08;
}
&:not(:hover)::before {
opacity: 0;
}
}
&.limegreen {
background: $p1-light-green;
color: black !important;
border: thin solid $p1-light-green !important;
}
&.not-operable {
background-color: rgba(255, 255, 255, 0.12) !important;
border: thin solid transparent !important;
pointer-events: none !important;
}
}
.v-dialog { .v-dialog {
label.available-seats-label { label.available-seats-label {
color: white; color: white;
...@@ -392,91 +321,12 @@ body { ...@@ -392,91 +321,12 @@ body {
} }
} }
.theme--light { .theme--light {
.filter-search {
div {
padding: 0;
&::before {
border-color: unset !important;
}
}
label {
/* design does not have a label or placeholder
for the search bar */
display: none;
}
/* no underline when active */
.v-text-field > .v-input__control > .v-input__slot:after {
width: 0 !important;
}
.v-text-field {
margin-top: -7px;
background: white;
border-radius: 5px !important;
color: $p1-light-green;
max-width: 250px;
.v-input__slot::before,
.v-input__control::before {
width: 0 !important;
display: none;
}
.v-input__control::after {
width: 0 !important;
display: none;
}
input {
color: black;
padding-left: 5px;
}
label {
color: black;
padding-left: 10px;
}
.v-icon {
color: black;
padding-right: 10px;
}
}
}
a.v-btn.secondary { a.v-btn.secondary {
span { span {
color: white; color: white;
} }
} }
button {
&.table-action-btn {
background: #272727 !important;
color: white;
}
&.dark-btn {
background: rgb(3, 19, 33) !important;
color: white !important;
span.v-btn__content {
color: white !important;
}
}
&.light-btn {
background: white !important;
color: black !important;
span.v-btn__content {
color: black !important;
}
}
}
a { a {
color: black !important; color: black !important;
} }
...@@ -485,10 +335,6 @@ body { ...@@ -485,10 +335,6 @@ body {
text-decoration: underline; text-decoration: underline;
} }
.dark-button {
color: white !important;
}
.v-application a { .v-application a {
color: #021421 !important; color: #021421 !important;
} }
...@@ -501,11 +347,6 @@ body { ...@@ -501,11 +347,6 @@ body {
color: map-get($material-light, "text-color"); color: map-get($material-light, "text-color");
} }
a.link-to-team {
text-transform: capitalize;
color: #0d6b90 !important;
}
.v-expansion-panel-header { .v-expansion-panel-header {
background-color: #f8f8f8; background-color: #f8f8f8;
} }
...@@ -595,8 +436,14 @@ body { ...@@ -595,8 +436,14 @@ body {
} }
.v-data-table { .v-data-table {
a:hover:not(.v-btn--icon) {
text-decoration: underline;
}
td { td {
border-bottom: none !important; border-bottom: none !important;
padding-top: 8px !important;
padding-bottom: 8px !important;
} }
// update paging footer to fit on one row in mobile // update paging footer to fit on one row in mobile
...@@ -642,12 +489,6 @@ body { ...@@ -642,12 +489,6 @@ body {
} }
.v-btn { .v-btn {
&.secondary {
color: map-get($material-light, "background-accent-2");
}
&.v-btn--outlined.secondary--text {
border-color: #e9e9e9;
}
&.no-link.v-btn--active { &.no-link.v-btn--active {
&::before { &::before {
opacity: 0.08; opacity: 0.08;
......
...@@ -3,8 +3,6 @@ $bottom-bg-color: #04243a; ...@@ -3,8 +3,6 @@ $bottom-bg-color: #04243a;
$text-color: #ffffff; $text-color: #ffffff;
$dark-bg-color: #002743; $dark-bg-color: #002743;
$button-text-color: #000000;
$gradient-alpha: #00000000; $gradient-alpha: #00000000;
$p1-light-green: #bdc931; $p1-light-green: #bdc931;
...@@ -17,9 +15,6 @@ $bottom-bg: #031727; ...@@ -17,9 +15,6 @@ $bottom-bg: #031727;
$link-color: #ffffff; $link-color: #ffffff;
$link-hover-color: #efefef; $link-hover-color: #efefef;
$button-border-color: #002743;
$button-border: 0.5px solid $button-border-color !important;
$table-row-even-bg: #15283a; $table-row-even-bg: #15283a;
$table-row-odd-bg: #010e19; $table-row-odd-bg: #010e19;
...@@ -30,6 +25,7 @@ $table-row-odd-bg-light: #fbfbfb; ...@@ -30,6 +25,7 @@ $table-row-odd-bg-light: #fbfbfb;
$body-font-family: "Open Sans", serif; $body-font-family: "Open Sans", serif;
$border-radius-root: 4px; $border-radius-root: 4px;
$font-size-root: 16px; $font-size-root: 16px;
$primary-button-text-color: #000000;
// Variables must come before the import // Variables must come before the import
$btn-font-weight: 600; $btn-font-weight: 600;
...@@ -54,10 +50,12 @@ $material-light: ( ...@@ -54,10 +50,12 @@ $material-light: (
background-accent-3: #efefef, background-accent-3: #efefef,
primary: #031322, primary: #031322,
text-color: #000000, text-color: #000000,
secondary-text-color: #ffffff,
); );
$material-dark: ( $material-dark: (
background: #04243a, background: #04243a,
background-accent-1: #15283a, background-accent-1: #15283a,
background-accent-2: #031322, background-accent-2: #031322,
text-color: #ffffff, text-color: #ffffff,
secondary-text-color: #000000,
); );
...@@ -36,7 +36,11 @@ ...@@ -36,7 +36,11 @@
<HelpDeskSummary slot="content" /> <HelpDeskSummary slot="content" />
</Section> </Section>
</v-col> </v-col>
<v-col cols="12" lg="6" class="d-flex flex-column py-0 pt-lg-3"> <v-col
cols="12"
lg="6"
class="d-flex flex-column py-0 pt-lg-3 mt-6 mt-lg-0"
>
<Section> <Section>
<h4 slot="header" class="ma-0 pl-5 text-left"> <h4 slot="header" class="ma-0 pl-5 text-left">
<TutorialTooltip tooltipName="projects"> <TutorialTooltip tooltipName="projects">
...@@ -49,7 +53,6 @@ ...@@ -49,7 +53,6 @@
<v-tooltip top> <v-tooltip top>
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn <v-btn
class="no-shadow no-border"
icon icon
v-bind="attrs" v-bind="attrs"
v-on="on" v-on="on"
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
<v-tooltip top> <v-tooltip top>
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn <v-btn
class="no-shadow no-border"
icon icon
v-bind="attrs" v-bind="attrs"
v-on="on" v-on="on"
......
...@@ -21,25 +21,15 @@ ...@@ -21,25 +21,15 @@
<v-spacer /> <v-spacer />
<v-btn <v-btn
v-if="canEdit && !loading && permission" v-if="canEdit && !loading && permission"
text
color="secondary" color="secondary"
class="no-border no-shadow primary mr-4" class="mr-4"
@click="exportTeams" @click="exportTeams"
> >
Export List Export List
</v-btn> </v-btn>
<v-btn <v-btn
v-if="canEdit && !loading && permission" v-if="canEdit && !loading && permission"
text color="primary"
color="secondary"
class="no-border no-shadow dark-button"
:class="{
'border-white': $vuetify.theme.dark,
limegreen: $vuetify.theme.dark,
secondary: !$vuetify.theme.dark,
'dark-button': !$vuetify.theme.dark,
tertiary: !$vuetify.theme.dark,
}"
@click="state.showEditDialog = true" @click="state.showEditDialog = true"
> >
Edit Team Details Edit Team Details
...@@ -65,7 +55,7 @@ ...@@ -65,7 +55,7 @@
lead or submit a ticket. lead or submit a ticket.
</p> </p>
<v-btn <v-btn
color="primary" color="tertiary"
href="https://jira.il2.dso.mil/servicedesk/customer/portal/1" href="https://jira.il2.dso.mil/servicedesk/customer/portal/1"
target="_blank" target="_blank"
class="mx-auto no-link" class="mx-auto no-link"
...@@ -103,16 +93,7 @@ ...@@ -103,16 +93,7 @@
<v-spacer /> <v-spacer />
<div v-if="permission"> <div v-if="permission">
<v-btn <v-btn
text color="tertiary"
color="secondary"
class="no-border no-shadow border-white"
:class="{
tertiary: $vuetify.theme.dark,
primary: !$vuetify.theme.dark,
limegreen: !$vuetify.theme.dark,
'not-operable':
availableSlots === 0 || state.isUndoingDelete,
}"
:disabled="availableSlots === 0 || state.isUndoingDelete" :disabled="availableSlots === 0 || state.isUndoingDelete"
@click="state.isAdding = true" @click="state.isAdding = true"
> >
...@@ -164,9 +145,7 @@ ...@@ -164,9 +145,7 @@
<template v-slot:actions> <template v-slot:actions>
<v-btn <v-btn
color="secondary" color="secondary"
class="secondary"
:disabled="state.isAddingBusy" :disabled="state.isAddingBusy"
text
@click="cancelAddMember()" @click="cancelAddMember()"
> >
Cancel Cancel
...@@ -175,7 +154,6 @@ ...@@ -175,7 +154,6 @@
:disabled="membersToAdd.length === 0 || isAddTeamMemberError" :disabled="membersToAdd.length === 0 || isAddTeamMemberError"
color="primary" color="primary"
:loading="state.isAddingBusy" :loading="state.isAddingBusy"
text
@click="addMember()" @click="addMember()"
> >
Add Member Add Member
...@@ -219,7 +197,8 @@ ...@@ -219,7 +197,8 @@
<template v-slot:footer> <template v-slot:footer>
<div class="d-flex my-3 mt-8"> <div class="d-flex my-3 mt-8">
<v-btn <v-btn
class="mr-3 table-action-btn" class="mr-3"
color="accent"
:disabled="selectedMembers.length === 0" :disabled="selectedMembers.length === 0"
:loading="state.isDeleting" :loading="state.isDeleting"
@click="removeSelected()" @click="removeSelected()"
...@@ -229,8 +208,8 @@ ...@@ -229,8 +208,8 @@
Remove Selected Remove Selected
</v-btn> </v-btn>
<v-btn <v-btn
class="mr-3 table-action-btn" class="mr-3"
:link="false" color="accent"
target="_blank" target="_blank"
@click="emailSelected" @click="emailSelected"
:disabled="selectedMembers.length === 0" :disabled="selectedMembers.length === 0"
...@@ -239,8 +218,7 @@ ...@@ -239,8 +218,7 @@
Email Selected Email Selected
</v-btn> </v-btn>
<v-btn <v-btn
class="no-link table-action-btn" color="accent"
:link="false"
@click="openDialogAddUsersToCourse()" @click="openDialogAddUsersToCourse()"
:disabled="selectedMembers.length === 0" :disabled="selectedMembers.length === 0"
> >
...@@ -574,10 +552,7 @@ export default { ...@@ -574,10 +552,7 @@ export default {
}, },
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
#back-button {
margin-left: 2px;
}
#team-table { #team-table {
.mt-n5px { .mt-n5px {
margin-top: -5px; margin-top: -5px;
...@@ -595,24 +570,11 @@ export default { ...@@ -595,24 +570,11 @@ export default {
pointer-events: none; pointer-events: none;
} }
} }
} .v-skeleton-loader__table-row .v-skeleton-loader__table-cell,
.v-skeleton-loader__table-row .v-skeleton-loader__table-cell, .v-skeleton-loader__table-thead .v-skeleton-loader__heading {
.v-skeleton-loader__table-thead .v-skeleton-loader__heading { &:nth-last-child(-n + 2) {
&:nth-last-child(-n + 2) { display: none;
display: none; }
} }
} }
#app .v-btn:not(.v-btn--outlined).primary {
color: black;
border: unset !important;
box-shadow: 1px 1px 1px black;
}
div.container.team
> div.d-flex.flex-column.justify-center.align-center.flex-sm-row.mb-n4
> button.no-border.no-shadow.primary.mr-4.v-btn.v-btn--text.theme--light.v-size--default.secondary--text {
background: white !important;
border: none !important;
}
</style> </style>
...@@ -6,25 +6,65 @@ ...@@ -6,25 +6,65 @@
type="table-heading,table-thead, table-tbody" type="table-heading,table-thead, table-tbody"
class="py-2" class="py-2"
> >
<div <v-row class="mb-4">
class="d-flex flex-wrap flex-sm-nowrap px-2 px-sm-4 justify-space-between align-items-center" <v-col cols="12" md="6">
> <h2 class="text-left px-0 my-0">
<div class="text-left">
<h3 class="px-0 text-left">
{{ trainingCourse.name }} {{ trainingCourse.name }}
</h3> </h2>
</div> </v-col>
<div> <v-col cols="12" md="6" class="text-right">
<router-link to="/training"> <v-btn
<v-btn color="secondary" class="mx-auto black"> color="primary"
Back to Courses @click="state.isAddingStudent = true"
</v-btn> class="mx-auto ml-4 black--text"
</router-link> >
</div> Add Student
</div> </v-btn>
<v-spacer /> <v-dialog
<h4 class="text-left" style="padding-left: 1em">Instructors</h4> v-model="state.isAddingStudent"
<div class="vertical-spacer"></div> persistent
no-click-animation
max-width="500px"
>
<v-card>
<v-card-title>
<span class="headline"
>Add new student to {{ currentTrainingCourse.name }}</span
>
</v-card-title>
<v-card-text>
<UserSelect
ref="userSelect"
v-model="studentToAdd"
multiple
required
/>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="secondary"
:disabled="state.isAddingBusy"
@click="cancelAddStudent()"
>
Cancel
</v-btn>
<v-btn
:disabled="state.isAddingDuplicate || !studentToAdd"
color="primary"
:loading="state.isAddingBusy"
text
@click="addStudent()"
>
Add Student
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-col>
</v-row>
<v-data-table <v-data-table
v-model="selectedInstructors" v-model="selectedInstructors"
id="training-table" id="training-table"
...@@ -32,6 +72,7 @@ ...@@ -32,6 +72,7 @@
:items="trainingCourse.instructorsCombined" :items="trainingCourse.instructorsCombined"
hide-default-footer hide-default-footer
mobile-breakpoint="800" mobile-breakpoint="800"
calculate-widths
:loading="loading" :loading="loading"
> >
<template v-slot:top> <template v-slot:top>
...@@ -218,7 +259,9 @@ ...@@ -218,7 +259,9 @@
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn text @click="cancelUpdateCourse"> Cancel </v-btn> <v-btn color="secondary" @click="cancelUpdateCourse">
Cancel
</v-btn>
<v-btn <v-btn
:disabled="!valid" :disabled="!valid"
color="primary" color="primary"
...@@ -258,7 +301,7 @@ ...@@ -258,7 +301,7 @@
</template> </template>
<template v-slot:[`item.availability`]> <template v-slot:[`item.availability`]>
<div class="d-flex align-items-center px-2 mt-n6"> <div class="d-flex align-items-center px-2">
<v-progress-linear <v-progress-linear
class="availability-bar" class="availability-bar"
rounded rounded
...@@ -299,15 +342,17 @@ ...@@ -299,15 +342,17 @@
</v-data-table> </v-data-table>
<div class="d-flex flex-wrap my-5"> <div class="d-flex flex-wrap my-5">
<v-btn class="mr-3 table-action-btn" @click="btnPushEditPoc"> <v-btn class="mr-3" @click="btnPushEditPoc" color="accent">
<v-icon class="mr-2">mdi-pencil</v-icon> <v-icon class="mr-2">mdi-pencil</v-icon>
Edit Course Edit Course
</v-btn> </v-btn>
</div> </div>
<TrainingAttendance <TrainingAttendance
class="px-0"
v-if="trainingCourse.id" v-if="trainingCourse.id"
:trainingCourse="trainingCourse" :trainingCourse="trainingCourse"
:reload="trigger"
/> />
</v-skeleton-loader> </v-skeleton-loader>
</v-container> </v-container>
...@@ -320,6 +365,7 @@ import inputRules from "@/utils/inputRules"; ...@@ -320,6 +365,7 @@ import inputRules from "@/utils/inputRules";
import TrainingAttendance from "@/components/Training/TrainingAttendance"; import TrainingAttendance from "@/components/Training/TrainingAttendance";
import { SET_ERROR_MESSAGE, SET_ERROR_DIALOG } from "@/store/mutation-types"; import { SET_ERROR_MESSAGE, SET_ERROR_DIALOG } from "@/store/mutation-types";
import UserSelect from "@/components/UserSelect"; import UserSelect from "@/components/UserSelect";
import { DEFAULT_PAGINATION_PARAMS } from "@/config/table-constants";
export default { export default {
components: { TrainingAttendance, UserSelect }, components: { TrainingAttendance, UserSelect },
...@@ -330,11 +376,19 @@ export default { ...@@ -330,11 +376,19 @@ export default {
trainingCourse: {}, trainingCourse: {},
trainingCourseSnapshot: {}, trainingCourseSnapshot: {},
selectedInstructorsSnapshot: [], selectedInstructorsSnapshot: [],
listItems: [],
inputRules, inputRules,
valid: true, valid: true,
trigger: 0,
studentToAdd: [],
state: { state: {
isEditingCourse: false, isEditingCourse: false,
isHoveringSeats: false, isHoveringSeats: false,
isAddingStudent: false,
isAddingDuplicate: false,
},
params: {
...DEFAULT_PAGINATION_PARAMS,
}, },
pocHeaders: [ pocHeaders: [
{ text: "Instructor", value: "name", width: "200px", sortable: false }, { text: "Instructor", value: "name", width: "200px", sortable: false },
...@@ -363,6 +417,28 @@ export default { ...@@ -363,6 +417,28 @@ export default {
todaysDate: moment(), // cannot be formatted if used with diff comparison in courseProgress todaysDate: moment(), // cannot be formatted if used with diff comparison in courseProgress
}), }),
computed: { computed: {
currentTrainingCourse() {
return this.trainingCourse;
},
courseLengthInDays() {
let days = 0;
const { startDate, endDate } = this.currentTrainingCourse;
const start = moment(startDate);
const end = moment(endDate);
if (start.isValid() && end.isValid()) {
days = end.diff(start, "days") + 1; //diff of days, include start date
}
return days;
},
courseDates() {
const days = this.courseLengthInDays;
const { startDate } = this.trainingCourse;
const dates = [];
for (let i = 0; i < days; i++) {
dates.push(moment(startDate).add(i, "d").format("YYYY-MM-DD"));
}
return dates;
},
courseProgress() { courseProgress() {
try { try {
const startDate = moment(this.trainingCourse.startDate, "YYYY-MM-DD"); const startDate = moment(this.trainingCourse.startDate, "YYYY-MM-DD");
...@@ -391,6 +467,12 @@ export default { ...@@ -391,6 +467,12 @@ export default {
this.initialLoad = false; this.initialLoad = false;
}, },
methods: { methods: {
cancelAddStudent() {
this.studentToAdd = null;
this.state.isAddingStudent = false;
this.state.isAddingDuplicate = false;
this.$refs.userSelect && this.$refs.userSelect.clear();
},
async fetchData() { async fetchData() {
try { try {
const response = await TrainingService.getCourse( const response = await TrainingService.getCourse(
...@@ -401,16 +483,46 @@ export default { ...@@ -401,16 +483,46 @@ export default {
registrations: true, registrations: true,
} }
); );
response.instructorsCombined = [ response.instructorsCombined = [
{ name: response.instructors.map((obj) => obj.name).join(", ") }, { name: response.instructors.map((obj) => obj.name).join(", ") },
]; ];
this.selectedInstructors = response.instructors; this.selectedInstructors = response.instructors;
this.trainingCourse = response; this.trainingCourse = response;
} catch (e) { } catch (e) {
this.$store.commit(SET_ERROR_MESSAGE, e); this.$store.commit(SET_ERROR_MESSAGE, e);
this.$store.commit(SET_ERROR_DIALOG, true); this.$store.commit(SET_ERROR_DIALOG, true);
} finally {
this.fetchStudentData();
}
},
async fetchStudentData() {
try {
const studentResponse = await TrainingService.getCourseRegistrationsById(
this.$route.params.trainingId,
{ ...this.params, attendance: true }
);
this.listItems =
studentResponse.registrations?.map((item) => {
item.completed = { value: item.completed, loading: false };
if (item.attendance.length !== 0) {
item.attendance.forEach((attendanceItem) => {
item[attendanceItem.date] = {
attended: attendanceItem.attended,
loading: false,
};
});
}
// set course attendance default to attended, unless already defined (from DB)
this.courseDates.forEach((date) => {
if (!item[date]) {
item[date] = { attended: true, loading: false };
}
});
return item;
}) || [];
} catch (e) {
this.$store.commit(SET_ERROR_MESSAGE, e);
this.$store.commit(SET_ERROR_DIALOG, true);
} }
}, },
btnPushEditPoc() { btnPushEditPoc() {
...@@ -423,6 +535,13 @@ export default { ...@@ -423,6 +535,13 @@ export default {
this.trainingCourseSnapshot = { ...this.trainingCourse }; this.trainingCourseSnapshot = { ...this.trainingCourse };
this.state.isEditingCourse = true; this.state.isEditingCourse = true;
}, },
fetchDebounced() {
// cancel pending call
clearTimeout(this._timerId);
this.fetchingData = true;
// delay new call
this.fetchData();
},
async updateCourse() { async updateCourse() {
this.loading = true; this.loading = true;
...@@ -446,90 +565,41 @@ export default { ...@@ -446,90 +565,41 @@ export default {
cancelUpdateCourse() { cancelUpdateCourse() {
this.state.isEditingCourse = false; this.state.isEditingCourse = false;
}, },
async addStudent(student) {
if (!student) {
student = this.studentToAdd;
}
this.state.isAddingBusy = true;
try {
await TrainingService.addStudents(
this.currentTrainingCourse.id,
student
);
this.studentToAdd = student;
this.trigger = this.trigger + 1;
} catch (error) {
console.error("addStudent error!!: ", error);
this.$store.commit(SET_ERROR_MESSAGE, error);
} finally {
this.state.isAddingBusy = false;
this.state.isAddingStudent = false;
this.$refs.userSelect && this.$refs.userSelect.clear();
}
},
}, },
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.black {
color: black !important;
}
#alternate-progress-bar-parent { #alternate-progress-bar-parent {
height: 8px; height: 8px;
} }
#alternate-progress-bar {
border-radius: 0;
}
#alternate-progress-bar > div.primary {
/* overriding green progress bar */
background-color: #7e92a5 !important;
}
#alternate-progress-bar-complete > div.primary { #alternate-progress-bar-complete > div.primary {
/* overriding green progress bar */ /* overriding green progress bar */
background-color: #bdc931 !important; background-color: var(--v-primary-base) !important;
}
#alternate-progress-bar > .v-progress-linear__background {
/* overriding background progress bar */
background-color: #404040 !important;
} }
#training-table .availability-bar { #training-table .availability-bar {
width: 100% !important; width: 100% !important;
} }
#training-table th > .v-data-table__checkbox {
display: none;
}
#training-table td {
padding-top: 1em;
padding-bottom: 4em;
}
.vertical-spacer {
height: 1em;
}
.text-container.d-flex > div {
padding-top: unset !important;
}
.button-container {
padding-top: unset !important;
margin-bottom: unset !important;
}
.view-wrapper.hover {
padding-top: 0;
}
.text-left > .d-flex {
height: 48px;
}
#training-table
> div.v-data-table__wrapper
> table
> tbody
> tr
> td:nth-child(5),
#training-table
> div.v-data-table__wrapper
> table
> tbody
> tr
> td:nth-child(5)
> div
> div
> div {
padding: 0 !important;
}
p {
margin: 0;
}
</style> </style>
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn <v-btn
color="secondary" color="secondary"
class="no-border no-shadow no-link ml-2 light-btn" class="no-link ml-2"
target="_blank" target="_blank"
@click="isExporting = true" @click="isExporting = true"
v-bind="attrs" v-bind="attrs"
...@@ -58,13 +58,12 @@ ...@@ -58,13 +58,12 @@
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn color="" text @click="isExporting = false"> <v-btn color="secondary" text @click="isExporting = false">
Cancel Cancel
</v-btn> </v-btn>
<v-btn <v-btn
color="primary"
:loading="isExportingActive" :loading="isExportingActive"
text
class="light-btn"
@click="exportList" @click="exportList"
> >
Export List Export List
...@@ -84,8 +83,8 @@ ...@@ -84,8 +83,8 @@
> >
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn <v-btn
class="no-border no-shadow no-link ml-2 dark-btn" class="ml-2"
target="_blank" color="primary"
@click="personnel.userSelect.isAddingPersonnel = true" @click="personnel.userSelect.isAddingPersonnel = true"
v-bind="attrs" v-bind="attrs"
v-on="on" v-on="on"
...@@ -118,9 +117,8 @@ ...@@ -118,9 +117,8 @@
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="" color="secondary"
:disabled="state.isAddingBusy" :disabled="state.isAddingBusy"
text
@click="cancelAddPersonnel" @click="cancelAddPersonnel"
> >
Cancel Cancel
...@@ -132,7 +130,6 @@ ...@@ -132,7 +130,6 @@
" "
color="primary" color="primary"
:loading="personnel.userSelect.isAddingBusy" :loading="personnel.userSelect.isAddingBusy"
text
@click="addPersonnel" @click="addPersonnel"
> >
Add Personnel Add Personnel
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment