-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(orga): create attestations page
- Loading branch information
1 parent
b03787f
commit fe104f7
Showing
12 changed files
with
412 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import PixButton from '@1024pix/pix-ui/components/pix-button'; | ||
import PixMultiSelect from '@1024pix/pix-ui/components/pix-multi-select'; | ||
import { on } from '@ember/modifier'; | ||
import { action } from '@ember/object'; | ||
import Component from '@glimmer/component'; | ||
import { tracked } from '@glimmer/tracking'; | ||
import { t } from 'ember-intl'; | ||
|
||
export default class AttestationsSixthGrade extends Component { | ||
@tracked selectedDivisions = []; | ||
|
||
@action | ||
onSubmit(event) { | ||
event.preventDefault(); | ||
|
||
this.args.onSubmit(this.selectedDivisions); | ||
} | ||
|
||
@action | ||
onSelectDivision(value) { | ||
this.selectedDivisions = value; | ||
} | ||
|
||
get isDisabled() { | ||
return !this.selectedDivisions.length; | ||
} | ||
|
||
<template> | ||
<h1 class="attestations-page__title">{{t "pages.attestations.title"}}</h1> | ||
|
||
<p class="attestations-page__text"> | ||
{{t "pages.attestations.description" htmlSafe=true}} | ||
</p> | ||
|
||
<form class="attestations-page__action" {{on "submit" this.onSubmit}}> | ||
<PixMultiSelect | ||
@options={{@divisions}} | ||
@values={{this.selectedDivisions}} | ||
@onChange={{this.onSelectDivision}} | ||
@placeholder={{t "pages.attestations.placeholder"}} | ||
> | ||
<:label>{{t "pages.attestations.select-label"}}</:label> | ||
<:default as |option|>{{option.label}}</:default> | ||
</PixMultiSelect> | ||
<PixButton @type="submit" id="download_attestations" @size="small" @isDisabled={{this.isDisabled}}> | ||
{{t "pages.attestations.download-attestations-button"}} | ||
</PixButton> | ||
</form> | ||
</template> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import Controller from '@ember/controller'; | ||
import { action } from '@ember/object'; | ||
import { service } from '@ember/service'; | ||
|
||
export const SIXTH_GRADE_ATTESTATION_KEY = 'SIXTH_GRADE'; | ||
export const SIXTH_GRADE_ATTESTATION_FILE_NAME = 'attestations'; | ||
|
||
export default class AuthenticatedAttestationsController extends Controller { | ||
@service fileSaver; | ||
@service session; | ||
@service currentUser; | ||
@service notifications; | ||
|
||
@action | ||
async downloadSixthGradeAttestationsFile(selectedDivisions) { | ||
try { | ||
const organizationId = this.currentUser.organization.id; | ||
const formatedDivisionsForQuery = selectedDivisions | ||
.map((division) => `divisions[]=${encodeURIComponent(division)}`) | ||
.join('&'); | ||
|
||
const url = `/api/organizations/${organizationId}/attestations/${SIXTH_GRADE_ATTESTATION_KEY}?${formatedDivisionsForQuery}`; | ||
|
||
const token = this.session.isAuthenticated ? this.session.data.authenticated.access_token : ''; | ||
|
||
await this.fileSaver.save({ url, token, fileName: SIXTH_GRADE_ATTESTATION_FILE_NAME }); | ||
} catch (error) { | ||
this.notifications.sendError(error.message, { autoClear: false }); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Route from '@ember/routing/route'; | ||
import { service } from '@ember/service'; | ||
|
||
export default class AuthenticatedAttestationsRoute extends Route { | ||
@service currentUser; | ||
@service router; | ||
|
||
beforeModel() { | ||
if (!this.currentUser.canAccessAttestationsPage) { | ||
this.router.replaceWith('application'); | ||
} | ||
} | ||
|
||
async model() { | ||
const divisions = await this.currentUser.organization.divisions; | ||
const options = divisions.map(({ name }) => ({ label: name, value: name })); | ||
return { options }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
.attestations-page { | ||
display: flex; | ||
flex-direction: column; | ||
|
||
&__title { | ||
@extend %pix-title-m; | ||
margin-bottom: var(--pix-spacing-8x); | ||
} | ||
|
||
&__text { | ||
@extend %pix-body-m; | ||
margin-bottom: var(--pix-spacing-8x); | ||
|
||
//margin: 2px 0 32px 0; | ||
|
||
} | ||
|
||
&__action { | ||
display: flex; | ||
flex-direction: column; | ||
flex-wrap: wrap; | ||
gap: var(--pix-spacing-4x); | ||
align-items: start; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{{page-title (t "pages.attestations.title")}} | ||
|
||
<div class="attestations-page"> | ||
<Attestations::SixthGrade @divisions={{@model.options}} @onSubmit={{this.downloadSixthGradeAttestationsFile}} /> | ||
</div> |
75 changes: 75 additions & 0 deletions
75
orga/tests/integration/components/attestations/sixth-grade-test.gjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { render } from '@1024pix/ember-testing-library'; | ||
import { click } from '@ember/test-helpers'; | ||
import { t } from 'ember-intl/test-support'; | ||
import SixthGrade from 'pix-orga/components/attestations/sixth-grade'; | ||
import { module, test } from 'qunit'; | ||
import sinon from 'sinon'; | ||
|
||
import setupIntlRenderingTest from '../../../helpers/setup-intl-rendering'; | ||
|
||
module('Integration | Component | Attestations | Sixth-grade', function (hooks) { | ||
setupIntlRenderingTest(hooks); | ||
|
||
test('it should display all basics informations', async function (assert) { | ||
// given | ||
const onSubmit = sinon.stub(); | ||
const divisions = []; | ||
|
||
// when | ||
const screen = await render(<template><SixthGrade @divisions={{divisions}} @onSubmit={{onSubmit}} /></template>); | ||
|
||
// then | ||
assert.ok(screen.getByRole('heading', { name: t('pages.attestations.title') })); | ||
assert.ok( | ||
screen.getByText('Sélectionnez la classe pour laquelle vous souhaitez exporter les attestations au format PDF.', { | ||
exact: false, | ||
}), | ||
); | ||
assert.ok(screen.getByRole('button', { name: t('pages.attestations.select-label') })); | ||
assert.ok(screen.getByText(t('pages.attestations.placeholder'))); | ||
assert.ok(screen.getByRole('button', { name: t('pages.attestations.download-attestations-button') })); | ||
}); | ||
|
||
test('download button is disabled if there is no selected divisions', async function (assert) { | ||
// given | ||
const onSubmit = sinon.stub(); | ||
const divisions = []; | ||
|
||
// when | ||
const screen = await render(<template><SixthGrade @divisions={{divisions}} @onSubmit={{onSubmit}} /></template>); | ||
|
||
// then | ||
const downloadButton = await screen.getByRole('button', { | ||
name: t('pages.attestations.download-attestations-button'), | ||
}); | ||
assert.dom(downloadButton).isDisabled(); | ||
}); | ||
|
||
test('it should call onSubmit action with selected divisions', async function (assert) { | ||
// given | ||
const onSubmit = sinon.stub(); | ||
|
||
const divisions = [{ label: 'division1', value: 'division1' }]; | ||
|
||
// when | ||
const screen = await render(<template><SixthGrade @divisions={{divisions}} @onSubmit={{onSubmit}} /></template>); | ||
|
||
const multiSelect = await screen.getByRole('button', { name: t('pages.attestations.select-label') }); | ||
await click(multiSelect); | ||
|
||
const firstDivisionOption = await screen.findByRole('checkbox', { name: 'division1' }); | ||
await click(firstDivisionOption); | ||
|
||
const downloadButton = await screen.getByRole('button', { | ||
name: t('pages.attestations.download-attestations-button'), | ||
}); | ||
|
||
// we need to get out of input choice to click on download button, so we have to click again on the multiselect to close it | ||
await click(multiSelect); | ||
await click(downloadButton); | ||
|
||
// then | ||
sinon.assert.calledWithExactly(onSubmit, ['division1']); | ||
assert.ok(true); | ||
}); | ||
}); |
93 changes: 93 additions & 0 deletions
93
orga/tests/unit/controllers/authenticated/attestations-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import Service from '@ember/service'; | ||
import { | ||
SIXTH_GRADE_ATTESTATION_FILE_NAME, | ||
SIXTH_GRADE_ATTESTATION_KEY, | ||
} from 'pix-orga/controllers/authenticated/attestations'; | ||
import { module, test } from 'qunit'; | ||
import sinon from 'sinon'; | ||
|
||
import setupIntlRenderingTest from '../../../helpers/setup-intl-rendering'; | ||
|
||
module('Unit | Controller | authenticated/attestations', function (hooks) { | ||
setupIntlRenderingTest(hooks); | ||
|
||
module('#downloadSixthGradeAttestationsFile', function () { | ||
test('should call the file-saver service with the right parameters', async function (assert) { | ||
// given | ||
const controller = this.owner.lookup('controller:authenticated/attestations'); | ||
|
||
const token = 'a token'; | ||
const organizationId = 12345; | ||
const selectedDivision = ['3èmea']; | ||
|
||
controller.session = { | ||
isAuthenticated: true, | ||
data: { | ||
authenticated: { | ||
access_token: token, | ||
}, | ||
}, | ||
}; | ||
|
||
controller.currentUser = { | ||
organization: { | ||
id: organizationId, | ||
}, | ||
}; | ||
|
||
controller.fileSaver = { | ||
save: sinon.stub(), | ||
}; | ||
|
||
controller.model = { | ||
options: [{ label: '3èmeA', value: '3èmeA' }], | ||
}; | ||
|
||
// when | ||
await controller.downloadSixthGradeAttestationsFile(selectedDivision); | ||
|
||
// then | ||
assert.ok( | ||
controller.fileSaver.save.calledWith({ | ||
token, | ||
url: `/api/organizations/${organizationId}/attestations/${SIXTH_GRADE_ATTESTATION_KEY}?divisions[]=${encodeURIComponent(selectedDivision)}`, | ||
fileName: SIXTH_GRADE_ATTESTATION_FILE_NAME, | ||
}), | ||
); | ||
}); | ||
|
||
test('it should not call file-save service and display an error if an error occurs', async function (assert) { | ||
// given | ||
const controller = this.owner.lookup('controller:authenticated/attestations'); | ||
const selectedDivision = ['3emeA']; | ||
const organizationId = 123; | ||
const errorMessage = 'oops'; | ||
|
||
controller.currentUser = { | ||
organization: { | ||
id: organizationId, | ||
}, | ||
}; | ||
controller.fileSaver = { | ||
save: sinon.stub(), | ||
}; | ||
controller.fileSaver.save.rejects(new Error(errorMessage)); | ||
|
||
controller.model = { | ||
options: [{ label: '3èmeA', value: '3èmeA' }], | ||
}; | ||
class NotificationsStub extends Service { | ||
sendError = errorMock; | ||
} | ||
this.owner.register('service:notifications', NotificationsStub); | ||
const errorMock = sinon.stub(); | ||
|
||
// when | ||
await controller.downloadSixthGradeAttestationsFile(selectedDivision); | ||
|
||
// then | ||
sinon.assert.calledWith(errorMock, errorMessage, { autoClear: false }); | ||
assert.ok(true); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.