Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature branch/data quality #6473

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
271ed96
start adding delete-staff-record component
kapppa-joe Dec 24, 2024
44356e7
add confirm and cancel buttons
kapppa-joe Jan 2, 2025
52bd07b
implement validation and error msg
kapppa-joe Jan 2, 2025
dc38c57
add call to deleteWorker
kapppa-joe Jan 2, 2025
dafcfa5
adding a textbox for other reason
kapppa-joe Jan 3, 2025
9047a9f
add unit test for other reason textbox
kapppa-joe Jan 3, 2025
b25abac
add unit tests related to other leave reason and additional details text
kapppa-joe Jan 3, 2025
23bd3a0
add a migration to change the text for worker leave reasons
kapppa-joe Jan 3, 2025
6459121
update the link of delete staff record button to new page
kapppa-joe Jan 3, 2025
f438ca6
add character count to page
kapppa-joe Jan 6, 2025
4dbdacb
bugfix and refactoring for CharacterCount component
kapppa-joe Jan 6, 2025
9980ab8
correct wrong path name in routing table and link
kapppa-joe Jan 6, 2025
face38a
amend character counts to be able to work with {updateOn: submit}
kapppa-joe Jan 6, 2025
b8e6e1f
refactoring
kapppa-joe Jan 6, 2025
ad932ab
Add workplace name address component
ssrome Jan 6, 2025
ec2aa4c
adjust css
kapppa-joe Jan 7, 2025
3cc9f71
delete the old delete-worker-dialog component
kapppa-joe Jan 7, 2025
a985081
update alert message
kapppa-joe Jan 7, 2025
ddfcecb
add scroll to error summary
kapppa-joe Jan 7, 2025
7cccd12
text update
kapppa-joe Jan 8, 2025
f52010f
minor fix
kapppa-joe Jan 8, 2025
829c59d
Create new column on login table for lastViewedSLVMessage and add to …
duncanc19 Jan 6, 2025
807587e
Create page with content and Continue button which goes to dashboard
duncanc19 Jan 6, 2025
5b39bce
Refactor login component spec file to use overrides
duncanc19 Jan 6, 2025
b3cbd4c
Update login spec tests to trigger user events rather than set form s…
duncanc19 Jan 6, 2025
a68d51f
Add tests around navigation after login and refactor
duncanc19 Jan 6, 2025
1b2f943
Navigate to new page when edit user and lastViewedSLVMessage in respo…
duncanc19 Jan 6, 2025
ddc7cbd
Add check for date last viewed message being over six months
duncanc19 Jan 6, 2025
c3f2e58
Add test for higher priority navigation
duncanc19 Jan 7, 2025
297d725
Add check for workplace being data owner to navigate to SLV message page
duncanc19 Jan 7, 2025
3fc182c
Set up call to user service from message page (with backend call stub…
duncanc19 Jan 7, 2025
679abce
Update PR to add new logic to User table to pass data from user more …
duncanc19 Jan 8, 2025
c16aa9f
Update login component to handle conversion of date from DB for last …
duncanc19 Jan 8, 2025
c337729
Add parent link and workplace address to dashboard header
ssrome Jan 9, 2025
eaea502
Add test file
ssrome Jan 9, 2025
fa3247c
Update content of message page
duncanc19 Jan 9, 2025
a5241ae
Rename component and function in user service
duncanc19 Jan 9, 2025
c1e7e12
Add return to url and update styles
ssrome Jan 9, 2025
00bc759
Change layout of workplace summary
ssrome Jan 9, 2025
4f90314
Merge branch 'main' into feat/1586-dq-workplace-restructure
ssrome Jan 9, 2025
ebe4233
Update spacing on message page
duncanc19 Jan 9, 2025
065f562
Rename new User table column and backend code to make more descriptive
duncanc19 Jan 9, 2025
35b04db
Refactor test to pass workplace
ssrome Jan 9, 2025
a90672b
Update variable on test
ssrome Jan 9, 2025
ccf5b49
Move backend call into onInit to ensure only called once
duncanc19 Jan 9, 2025
80e3cae
Add send to updateLastViewedVacanciesAndTurnoverMessage to stop endpo…
duncanc19 Jan 9, 2025
5989fc2
Use uuid package instead of own uid validation
duncanc19 Jan 10, 2025
1333c67
Merge pull request #6469 from NMDSdevopsServiceAdm/feat/1589-data-qua…
duncanc19 Jan 13, 2025
30afc49
Merge pull request #6471 from NMDSdevopsServiceAdm/feat/1586-dq-workp…
ssrome Jan 13, 2025
aec1e18
Merge pull request #6468 from NMDSdevopsServiceAdm/feat/1587-dq-reaso…
kapppa-joe Jan 13, 2025
6d3b715
Merge branch 'main' into feature-branch/data-quality
duncanc19 Jan 13, 2025
2bcd634
Merge branch 'main' into feature-branch/data-quality
duncanc19 Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict';
const models = require('../server/models/index');

const allReasons = [
{
id: 1,
seq: 1,
oldText: 'They moved to another adult social care employer',
newText: 'The worker moved to another adult social care employer',
},
{
id: 2,
seq: 2,
oldText: 'They moved to a role in the health sector',
newText: 'The worker moved to a role in the health sector',
},
{
id: 3,
seq: 3,
oldText: 'They moved to a different sector (e.g. retail)',
newText: 'The worker moved to a different sector (for example, retail)',
},
{
id: 4,
seq: 4,
oldText: 'They moved to another role in this organisation',
newText: 'The worker moved to a different role in this organisation',
},
{
id: 5,
seq: 5,
oldText: 'The worker chose to leave (destination unknown)',
newText: 'The worker chose to leave (destination not known)',
},
{ id: 6, seq: 6, oldText: 'The worker retired', newText: 'The worker retired' },
{
id: 7,
seq: 7,
oldText: 'Employer terminated their employment',
newText: 'The worker had their employment terminated',
},
{ id: 8, seq: 8, oldText: 'Other', newText: 'For a reason not listed' },
{ id: 9, seq: 9, oldText: 'Not known', newText: 'Reason not known' },
];

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface) {
return queryInterface.sequelize.transaction(async (transaction) => {
for (const reason of allReasons) {
await models.workerLeaveReasons.update(
{
reason: reason.newText,
},
{
where: {
id: reason.id,
},
transaction,
},
);
}
});
},

async down(queryInterface) {
return queryInterface.sequelize.transaction(async (transaction) => {
for (const reason of allReasons) {
await models.workerLeaveReasons.update(
{
reason: reason.oldText,
},
{
where: {
id: reason.id,
},
transaction,
},
);
}
});
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

const userTable = { tableName: 'User', schema: 'cqc' };

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
return queryInterface.addColumn(userTable, 'LastViewedVacanciesAndTurnoverMessage', {
type: Sequelize.DataTypes.DATE,
allowNull: true,
});
},

async down(queryInterface) {
return queryInterface.removeColumn(userTable, 'LastViewedVacanciesAndTurnoverMessage');
},
};
16 changes: 16 additions & 0 deletions backend/server/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,11 @@ module.exports = function (sequelize, DataTypes) {
allowNull: true,
field: '"CanManageWdfClaimsChangedBy"',
},
lastViewedVacanciesAndTurnoverMessage: {
type: DataTypes.DATE,
allowNull: true,
field: 'LastViewedVacanciesAndTurnoverMessage',
},
},
{
tableName: '"User"',
Expand Down Expand Up @@ -542,5 +547,16 @@ module.exports = function (sequelize, DataTypes) {
return userFound;
};

User.setDateForLastViewedVacanciesAndTurnoverMessage = async function (userUid) {
return await this.update(
{ lastViewedVacanciesAndTurnoverMessage: new Date() },
{
where: {
uid: userUid,
},
},
);
};

return User;
};
23 changes: 22 additions & 1 deletion backend/server/routes/accounts/user.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// default route for user endpoint
const express = require('express');
const router = express.Router();
const { validate } = require('uuid');

const models = require('../../models');
const Authorization = require('../../utils/security/isAuthenticated');
Expand Down Expand Up @@ -809,7 +810,7 @@ router.route('/swap/establishment/notification/:nmsdId').get(async (req, res) =>
let notificationArr = [];

const establishmentNotifications = await notifications.selectNotificationByEstablishment(req.establishmentUid);
if(establishmentNotifications) notificationArr.push(establishmentNotifications);
if (establishmentNotifications) notificationArr.push(establishmentNotifications);
return res.status(200).send(notificationArr);
}
} catch (e) {
Expand Down Expand Up @@ -911,6 +912,22 @@ const swapEstablishment = async (req, res) => {
.json(response);
};

const updateLastViewedVacanciesAndTurnoverMessage = async (req, res) => {
try {
const userUid = req.params?.userUid;

if (!validate(userUid)) {
return res.status(400).send('User UID invalid');
}

await models.user.setDateForLastViewedVacanciesAndTurnoverMessage(userUid);

return res.status(200).send('Last viewed date updated');
} catch (error) {
return res.status(500).send('Failed to update last viewed date');
}
};

router.route('/').get(return200);
router.route('/admin').get(Authorization.isAdmin, listAdminUsers);
router.route('/admin/:userId').get(Authorization.isAdmin, getUser);
Expand Down Expand Up @@ -945,6 +962,9 @@ router.route('/my/establishments').get(Authorization.isAuthorised, listEstablish
router.route('/admin/:userId').get(Authorization.isAuthorised, getUser);
router.use('/my/notifications', Authorization.isAuthorised);
router.route('/my/notifications').get(listNotifications);
router
.route('/update-last-viewed-vacancies-and-turnover-message/:userUid')
.post(Authorization.isAuthorised, updateLastViewedVacanciesAndTurnoverMessage);

router.use('/swap/establishment/:id', authLimiter);
router.route('/swap/establishment/:id').post(Authorization.isAdmin, swapEstablishment);
Expand All @@ -955,3 +975,4 @@ module.exports.partAddUser = partAddUser;

module.exports.listAdminUsers = listAdminUsers;
module.exports.updateUser = updateUser;
module.exports.updateLastViewedVacanciesAndTurnoverMessage = updateLastViewedVacanciesAndTurnoverMessage;
3 changes: 3 additions & 0 deletions backend/server/routes/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ router.post('/', async (req, res) => {
'UserRoleValue',
'registrationSurveyCompleted',
'tribalId',
'lastViewedVacanciesAndTurnoverMessage',
],
include: [
{
Expand All @@ -95,6 +96,7 @@ router.post('/', async (req, res) => {
'lastBulkUploaded',
'eightWeeksFromFirstLogin',
'EmployerTypeValue',
'dataOwner',
],
include: [
{
Expand Down Expand Up @@ -284,6 +286,7 @@ router.post('/', async (req, res) => {
migratedUser,
},
establishmentUser.user.registrationSurveyCompleted,
establishmentUser.user.lastViewedVacanciesAndTurnoverMessage,
);

await models.sequelize.transaction(async (t) => {
Expand Down
49 changes: 48 additions & 1 deletion backend/server/test/unit/routes/accounts/user.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@ const expect = chai.expect;
const sinon = require('sinon');
const httpMocks = require('node-mocks-http');

const { meetsMaxUserLimit, partAddUser, listAdminUsers, updateUser } = require('../../../../routes/accounts/user');
const {
meetsMaxUserLimit,
partAddUser,
listAdminUsers,
updateUser,
updateLastViewedVacanciesAndTurnoverMessage,
} = require('../../../../routes/accounts/user');
const User = require('../../../../models/classes/user').User;
const models = require('../../../../models');

describe('user.js', () => {
let req;
Expand Down Expand Up @@ -345,4 +352,44 @@ describe('user.js', () => {
});
});
});

describe('updateLastViewedVacanciesAndTurnoverMessage', () => {
let req;
let res;

beforeEach(() => {
req = httpMocks.createRequest();
res = httpMocks.createResponse();
});

it('should return 200 response if userUid in params is valid and database call successful', async () => {
req.params = { userUid: '6b6885fa-340d-4d59-8720-c03d8845e603' };
sinon.stub(models.user, 'setDateForLastViewedVacanciesAndTurnoverMessage').returns(null);

await updateLastViewedVacanciesAndTurnoverMessage(req, res);

expect(res.statusCode).to.equal(200);
expect(res._getData()).to.deep.equal('Last viewed date updated');
});

it('should return 400 response if userUid in params invalid', async () => {
req.params = { userUid: 'invalid-uid' };
sinon.stub(models.user, 'setDateForLastViewedVacanciesAndTurnoverMessage').returns(null);

await updateLastViewedVacanciesAndTurnoverMessage(req, res);

expect(res.statusCode).to.equal(400);
expect(res._getData()).to.deep.equal('User UID invalid');
});

it('should return 500 response if unexpected error', async () => {
req.params = { userUid: '6b6885fa-340d-4d59-8720-c03d8845e603' };
sinon.stub(models.user, 'setDateForLastViewedVacanciesAndTurnoverMessage').throws();

await updateLastViewedVacanciesAndTurnoverMessage(req, res);

expect(res.statusCode).to.equal(500);
expect(res._getData()).to.deep.equal('Failed to update last viewed date');
});
});
});
3 changes: 3 additions & 0 deletions backend/server/utils/login/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module.exports = (
agreedUpdatedTerms,
migratedUser,
registrationSurveyCompleted,
lastViewedVacanciesAndTurnoverMessage,
) => {
// note - the mainService can be null
return {
Expand All @@ -35,6 +36,7 @@ module.exports = (
parentName: establishment.parentName ? establishment.parentName : undefined,
isFirstBulkUpload: establishment.lastBulkUploaded ? false : true,
employerTypeSet: establishment.EmployerTypeValue ? true : false,
dataOwner: establishment.dataOwner,
}
: null,
mainService: establishment
Expand All @@ -45,5 +47,6 @@ module.exports = (
: null,
expiryDate: expiryDate,
registrationSurveyCompleted: registrationSurveyCompleted,
lastViewedVacanciesAndTurnoverMessage,
};
};
8 changes: 7 additions & 1 deletion frontend/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ import { FirstLoginPageComponent } from '@features/first-login-page/first-login-
import { ForgotYourPasswordComponent } from '@features/forgot-your-username-or-password/forgot-your-password/forgot-your-password.component';
import { ForgotYourUsernameOrPasswordComponent } from '@features/forgot-your-username-or-password/forgot-your-username-or-password.component';
import { ForgotYourUsernameComponent } from '@features/forgot-your-username-or-password/forgot-your-username/forgot-your-username.component';
import { UsernameFoundComponent } from '@features/forgot-your-username-or-password/username-found/username-found.component';
import { SecurityQuestionAnswerNotMatchComponent } from '@features/forgot-your-username-or-password/forgot-your-username/security-question-answer-not-match/security-question-answer-not-match.component';
import { UserAccountNotFoundComponent } from '@features/forgot-your-username-or-password/forgot-your-username/user-account-not-found/user-account-not-found.component';
import { UsernameFoundComponent } from '@features/forgot-your-username-or-password/username-found/username-found.component';
import { LoginComponent } from '@features/login/login.component';
import { VacanciesAndTurnoverLoginMessage } from '@features/login/vacancies-and-turnover-login-message/vacancies-and-turnover-login-message.component';
import { LogoutComponent } from '@features/logout/logout.component';
import { MigratedUserTermsConditionsComponent } from '@features/migrated-user-terms-conditions/migrated-user-terms-conditions.component';
import { BecomeAParentComponent } from '@features/new-dashboard/become-a-parent/become-a-parent.component';
Expand Down Expand Up @@ -148,6 +149,11 @@ const routes: Routes = [
component: MigratedUserTermsConditionsComponent,
data: { title: 'Migrated User Terms And Conditions' },
},
{
path: 'update-your-vacancies-and-turnover-data',
component: VacanciesAndTurnoverLoginMessage,
data: { title: 'Update your vacancies and turnover data' },
},
{
path: 'workplace',
loadChildren: () => import('@features/workplace/workplace.module').then((m) => m.WorkplaceModule),
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import { Angulartics2Module } from 'angulartics2';
import { HighchartsChartModule } from 'highcharts-angular';

import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
import { ErrorHandler, NgModule } from '@angular/core';
Expand Down Expand Up @@ -72,7 +69,9 @@ import { FindUsernameComponent } from '@features/forgot-your-username-or-passwor
import { ForgotYourUsernameComponent } from '@features/forgot-your-username-or-password/forgot-your-username/forgot-your-username.component';
import { SecurityQuestionAnswerNotMatchComponent } from '@features/forgot-your-username-or-password/forgot-your-username/security-question-answer-not-match/security-question-answer-not-match.component';
import { UserAccountNotFoundComponent } from '@features/forgot-your-username-or-password/forgot-your-username/user-account-not-found/user-account-not-found.component';
import { UsernameFoundComponent } from '@features/forgot-your-username-or-password/username-found/username-found.component';
import { LoginComponent } from '@features/login/login.component';
import { VacanciesAndTurnoverLoginMessage } from '@features/login/vacancies-and-turnover-login-message/vacancies-and-turnover-login-message.component';
import { LogoutComponent } from '@features/logout/logout.component';
import { BecomeAParentComponent } from '@features/new-dashboard/become-a-parent/become-a-parent.component';
import { DashboardWrapperComponent } from '@features/new-dashboard/dashboard-wrapper.component';
Expand All @@ -94,14 +93,15 @@ import { BenchmarksModule } from '@shared/components/benchmarks-tab/benchmarks.m
import { DataAreaTabModule } from '@shared/components/data-area-tab/data-area-tab.module';
import { FeatureFlagsService } from '@shared/services/feature-flags.service';
import { SharedModule } from '@shared/shared.module';
import { Angulartics2Module } from 'angulartics2';
import { HighchartsChartModule } from 'highcharts-angular';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { StaffMismatchBannerComponent } from './features/dashboard/home-tab/staff-mismatch-banner/staff-mismatch-banner.component';
import { MigratedUserTermsConditionsComponent } from './features/migrated-user-terms-conditions/migrated-user-terms-conditions.component';
import { SatisfactionSurveyComponent } from './features/satisfaction-survey/satisfaction-survey.component';
import { SentryErrorHandler } from './SentryErrorHandler.component';
import { UsernameFoundComponent } from '@features/forgot-your-username-or-password/username-found/username-found.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -151,6 +151,7 @@ import { UsernameFoundComponent } from '@features/forgot-your-username-or-passwo
SelectStarterJobRolesComponent,
SecurityQuestionAnswerNotMatchComponent,
UserAccountNotFoundComponent,
VacanciesAndTurnoverLoginMessage,
],
imports: [
Angulartics2Module.forRoot({
Expand Down
1 change: 1 addition & 0 deletions frontend/src/app/core/model/userDetails.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface UserDetails {
updatedBy?: string;
username?: string;
canManageWdfClaims?: boolean;
lastViewedVacanciesAndTurnoverMessage?: string;
}

export enum UserStatus {
Expand Down
Loading
Loading