Skip to content
Snippets Groups Projects
Commit 23d01128 authored by Pierre Ecarlat's avatar Pierre Ecarlat
Browse files

feat(orientation) - Update page to select one of our structures

parent 3e3eb17f
No related branches found
No related tags found
3 merge requests!783V3.0.0,!741making onboarding-infos-covid-2 up to date,!708feat(orientation): Update page to select one of our structures
Showing
with 323 additions and 185 deletions
......@@ -13,30 +13,13 @@
</div>
<div class="resultsInfo">
<div *ngIf="userList.length" class="users">
<div
<app-member-card
*ngFor="let user of userList"
class="singleUser"
tabindex="0"
role="link"
(click)="goToUser(user._id)"
(keyup.enter)="goToUser(user._id)"
>
<div class="left">
<app-svg-icon [folder]="'avatar'" [icon]="'defaultAvatar'" [iconClass]="'icon-48'" />
<div class="identity">
<p class="name">{{ user.name | userName }} {{ user.surname | uppercase }}</p>
<p *ngIf="user.job" class="job">{{ user.job.name }}</p>
<div *ngIf="user.withAppointment" class="appointment">
<app-svg-icon [iconClass]="'icon-20'" [folder]="'tags'" [icon]="'rdv'" />
<span>Rendez-vous</span>
</div>
</div>
</div>
<div class="right">
<div *ngIf="user.employer" class="employer">{{ user.employer.name }}</div>
<app-svg-icon [iconClass]="'icon-32'" [folder]="'ico'" [icon]="'chevronRight'" />
</div>
</div>
[member]="user"
[showAppointment]="true"
[showContactInfo]="false"
[showEmployer]="true"
/>
<div *ngIf="showPagination" class="pagination">
<p>{{ userList.length }} membres affichés sur {{ totalUserResult }}</p>
<app-v3-button
......
<div class="orientationForm">
<h2>Quelle structure oriente la personne&nbsp;?</h2>
<div *ngIf="hasStructures && structuresLinked.length >= 2" class="select-structure border">
<div class="number">{{ structuresLinked.length }} structures sont associées à votre compte</div>
<div
*ngFor="let structure of structuresLinked"
class="structure-item"
tabindex="0"
[ngClass]="{ 'item-selected': structure.structureName === selected?.structureName }"
(click)="select(structure)"
(keyup.enter)="select(structure)"
>
<div class="item-frame">
<div class="name">{{ structure.structureName }}</div>
<div class="commune">{{ structure.address.commune }}</div>
</div>
<app-svg-icon
*ngIf="structure.structureName === selected?.structureName"
class="form-icon"
[iconClass]="'icon-26'"
[folder]="'form'"
[icon]="'validate'"
/>
<div class="orientation-header">
<h2>Quelle structure oriente la personne&nbsp;?</h2>
<div *ngIf="hasStructures && structuresLinked.length >= 2" class="number">
{{ structuresLinked.length }} structures sont associées à votre compte
</div>
</div>
<div *ngIf="!hasStructures" class="select-structure">
<section *ngIf="hasStructures && structuresLinked.length >= 2">
<app-member-card [member]="profile" [showContactInfo]="false" [showEmployer]="false" [redirectToProfile]="false" />
<div class="structures-section">
<p>Sélectionnez la structure de votre choix</p>
<div class="list-structures">
<app-card
*ngFor="let structure of structuresLinked"
role="listitem"
[structure]="structure"
[redirectToStructure]="false"
[showRadioButton]="true"
[isChecked]="structure._id === selected?._id"
(selectedStructure)="select(structure)"
/>
</div>
</div>
</section>
<div *ngIf="!hasStructures">
<form [formGroup]="form">
<div>
<div class="form-group" fxLayout="column">
......
......@@ -3,34 +3,39 @@
@import 'inputs';
@import 'breakpoint';
.select-structure {
width: 380px;
.orientation-header {
display: flex;
flex-direction: column;
gap: 16px;
.number {
padding: 1rem;
color: $grey-3;
@include font-regular-13;
@include font-regular-18;
}
}
section {
border: 1px solid $grey-6;
border-radius: 8px;
::ng-deep .structureMember {
border-radius: 8px 8px 0px 0px;
}
&.border {
border: solid 2px $grey-9;
}
.structures-section {
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px;
p {
@include font-bold-16;
}
.structure-item {
cursor: pointer;
padding-left: 1rem;
height: 76px;
.list-structures {
display: flex;
align-items: center;
justify-content: space-between;
border: solid 2px transparent;
border-top-color: $grey-9;
&:hover {
.name {
text-decoration: underline;
}
}
&.item-selected {
border: solid 2px $green-1;
}
flex-direction: column;
gap: 24px;
}
}
......
<form *ngIf="owners?.length > 0 || (structures?.length > 0 && structuresListReady)" [formGroup]="form">
<form
*ngIf="owners?.length > 0 || (structures?.length > 0 && structuresListReady)"
class="orientationForm"
[formGroup]="form"
>
<div class="title">
<h3>Vous allez demander un rendez-vous :</h3>
<h3>Vous allez demander un rendez-vous avec :</h3>
</div>
<div *ngIf="owners?.length > 0">
<div class="header" tabindex="0" fxLayout="column">
<app-card
class="structure-card"
role="listitem"
[noDetails]="true"
[structure]="structureRDV"
[isOrientation]="false"
[isOrientationRdv]="false"
[isInteractive]="false"
/>
</div>
<div class="selectList">
<h4>Sélectionnez un·e accompagnant·e numérique</h4>
<div
*ngFor="let owner of owners"
class="card-single selected"
fxLayout="row"
fxLayoutAlign="left center"
fxLayoutGap="16px"
[ngClass]="{ selected: this.form.get('socialWorkerId')?.value === owner._id }"
>
<input
type="radio"
formControlName="socialWorkerId"
id="{{ owner._id }}"
value="{{ owner._id }}"
(change)="onSocialWorkerRadioChange(owner)"
<section *ngIf="owners?.length > 0">
<app-card [structure]="structureRDV" [redirectToStructure]="false" />
<div class="users-section">
<p>Sélectionnez un·e accompagnant·e numérique</p>
<div class="list-users">
<app-member-card
*ngFor="let owner of owners"
role="listitem"
[member]="owner"
[showRadioButton]="true"
[showContactInfo]="false"
[showEmployer]="false"
[isChecked]="this.form.get('socialWorkerId')?.value === owner._id"
(selectedCard)="onSocialWorkerRadioChange(owner)"
/>
<label for="{{ owner._id }}">
<app-svg-icon class="" [folder]="'avatar'" [icon]="'defaultAvatar'" [iconClass]="'icon-40'" />
<div fxLayout="column" fxLayoutAlign="start">
<div fxLayout="row" class="selectListNameContainer">
<span class="selectListName">{{ owner.name | userName }} {{ owner.surname | uppercase }}</span>
</div>
<span class="selectListJob">{{ owner.job?.name }}</span>
</div>
</label>
</div>
</div>
</div>
</section>
<div *ngIf="structures?.length > 0">
<div class="header" tabindex="0" fxLayout="column">
......@@ -83,10 +65,7 @@
<app-card
class="structure-card"
role="listitem"
[noDetails]="true"
[structure]="structure"
[isOrientation]="false"
[isOrientationRdv]="false"
(change)="onStructureRadioChange(structure)"
/>
</label>
......@@ -96,16 +75,14 @@
<div class="details">
<label for="details-field">Précisez les besoins de la personne (disponibilités...) :</label>
<div fxLayout="row" fxLayoutAlign="left center" fxLayoutGap="16px">
<textarea
formControlName="details"
id="details"
name="details-field"
rows="10"
maxlength="1000"
(change)="onDetailsChange()"
></textarea>
</div>
<textarea
formControlName="details"
id="details"
name="details-field"
rows="10"
maxlength="1000"
(change)="onDetailsChange()"
></textarea>
</div>
</form>
......
......@@ -25,6 +25,33 @@
width: 100%;
}
}
section {
border: 1px solid $grey-6;
border-radius: 8px;
::ng-deep .structure {
border-radius: 8px 8px 0px 0px;
}
}
.users-section {
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px;
p {
@include font-bold-16;
}
.list-users {
display: flex;
flex-direction: column;
gap: 24px;
}
}
.selectList {
padding: 0 32px 24px 48px;
border: 2px solid $grey-6;
......@@ -43,18 +70,9 @@
padding: 0 12px;
}
}
.selectListJob {
color: $grey-3;
@include font-regular-16;
font-style: italic;
}
.selectListNameContainer {
align-items: center;
}
.selectListName {
@include font-bold-18;
width: 100%;
}
h4 {
@include font-bold-18;
}
......@@ -73,7 +91,6 @@
}
}
.details {
margin-top: 40px;
label {
padding-bottom: 8px;
}
......
......@@ -140,6 +140,9 @@ export class MakeAppointmentComponent implements OnInit {
}
public onSocialWorkerRadioChange(socialWorker: Owner): void {
this.form.patchValue({
socialWorkerId: socialWorker._id,
});
this.socialWorker.emit(socialWorker);
this.checkValidation.emit();
}
......
......@@ -135,7 +135,12 @@
/>
</div>
<div class="sectionContent members">
<app-member-card *ngFor="let member of membersWithJobWithPO" [member]="member" />
<app-member-card
*ngFor="let member of membersWithJobWithPO"
[member]="member"
[redirectToProfile]="false"
[showEmployer]="false"
/>
</div>
</div>
<div
......
<div class="structureMember">
<app-svg-icon class="avatar hide-on-mobile" [folder]="'avatar'" [icon]="'defaultAvatar'" [iconClass]="'icon-40'" />
<div class="infoDetails">
<p class="name underline" tabindex="0" (click)="goToProfile()" (keyup.enter)="goToProfile()">
{{ member.name | userName }} {{ member.surname | uppercase }}
</p>
<div
class="structureMember"
[ngClass]="{ clickable: isInteractive(), isChecked: isChecked }"
[tabindex]="isInteractive() ? '0' : '-1'"
(click)="cardClicked()"
(keyup.enter)="cardClicked()"
>
<input *ngIf="showRadioButton" type="radio" tabindex="-1" id="{{ member._id }}" [checked]="isChecked" />
<app-svg-icon class="hide-on-mobile" [folder]="'avatar'" [icon]="'defaultAvatar'" [iconClass]="'icon-48'" />
<div class="infoDetails" [ngClass]="{ largeCard: showAppointment }">
<p class="name">{{ member.name | userName }} {{ member.surname | uppercase }}</p>
<p>{{ getJob() }}</p>
<div *ngIf="showAppointment && member.withAppointment" class="appointment">
<app-svg-icon [iconClass]="'icon-20'" [folder]="'tags'" [icon]="'rdv'" />
<span>Rendez-vous</span>
</div>
</div>
<div *ngIf="getPhone()" class="infoDetails">
<p>{{ getPhone() }}</p>
<p class="mail">{{ member.email }}</p>
<div *ngIf="showContactInfo" class="infoDetails">
<p *ngIf="getPhone()">{{ getPhone() }}</p>
<p *ngIf="getEmail()" class="mail">{{ getEmail() }}</p>
</div>
<div *ngIf="showEmployer && member.employer" class="right employer">{{ member.employer.name }}</div>
<app-svg-icon *ngIf="redirectToProfile" [iconClass]="'icon-32'" [folder]="'ico'" [icon]="'chevronRight'" />
</div>
......@@ -6,20 +6,34 @@
.structureMember {
@include font-regular-14;
display: flex;
flex-direction: row;
align-items: center;
gap: 24px;
padding: 1rem;
border: 1px solid $grey-7;
border-radius: 4px;
color: $grey-3;
transition: all 0.2s ease-in-out;
.avatar {
display: flex;
align-items: center;
background-color: $grey-9;
border-radius: 4px;
&.clickable {
&:hover {
border-color: $grey-4;
}
}
&.isChecked {
box-shadow: 0px 6px 12px 0px rgba(0, 0, 0, 0.1);
border-color: $red;
&:hover {
border-color: $red;
}
}
input {
accent-color: $grey-1;
width: 18px;
height: 18px;
margin: 6px;
cursor: pointer;
}
p {
......@@ -27,8 +41,6 @@
}
.name {
@include font-bold-16;
text-decoration: underline;
cursor: pointer;
color: $grey-1;
}
......@@ -36,12 +48,41 @@
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
gap: 8px;
flex-grow: 1;
flex-basis: 0;
&.largeCard {
height: 71px;
}
.appointment {
display: flex;
align-items: center;
gap: 0.5rem;
span {
@include font-bold-14;
}
}
}
.mail {
text-decoration: underline;
}
.right {
display: flex;
align-items: center;
gap: 1.5rem;
color: $grey-4;
.employer {
color: $grey-3;
}
}
::ng-deep svg {
top: 0px;
position: unset;
}
}
import { Component, Input } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Router } from '@angular/router';
import { get } from 'lodash';
import { Owner } from '../../../models/owner.model';
import { User } from '../../../models/user.model';
import { User, UserAnnuary } from '../../../models/user.model';
@Component({
selector: 'app-member-card',
templateUrl: './member-card.component.html',
styleUrls: ['./member-card.component.scss'],
})
export class MemberCardComponent {
@Input() public member: User | Owner;
export class MemberCardComponent implements OnInit {
// The user info to display
@Input({ required: true }) public member: User | Owner | UserAnnuary;
// If true, shows the RDV icon if available
@Input() public showAppointment = false;
// If true, shows the contact info (phone + email), if provided
@Input() public showContactInfo = true;
// If true, shows the employer
@Input() public showEmployer = true;
// If true, click event redirects to profile
@Input() public redirectToProfile = true;
// If true, shows a radio button to select the card, disables the redirection to profile
@Input() public showRadioButton = false;
// If true, checks the radioButton
@Input() public isChecked = false;
@Output() public selectedCard = new EventEmitter<string>();
constructor(private router: Router) {}
ngOnInit(): void {
if (this.showRadioButton && this.redirectToProfile) {
console.warn("Can't make a card redirect to a profile with a radio button.");
this.redirectToProfile = false;
}
}
isInteractive(): boolean {
return this.showRadioButton || this.redirectToProfile;
}
getJob(): string {
return this.member.job?.name ?? '';
}
......@@ -23,7 +55,16 @@ export class MemberCardComponent {
return get(this.member, 'phone') ?? false;
}
goToProfile(): void {
this.router.navigateByUrl(`/profile/${this.member._id}`);
/** Depending on User or UserAnnuary return the email of false */
getEmail(): string | false {
return get(this.member, 'email') ?? false;
}
cardClicked(): void {
if (this.redirectToProfile) {
this.router.navigateByUrl(`/profile/${this.member._id}`);
} else if (this.showRadioButton) {
this.selectedCard.emit(this.member._id);
}
}
}
<div
class="structure"
tabindex="0"
[ngClass]="{ orientation: isOrientation, interactive: isInteractive }"
[tabindex]="isInteractive() ? '0' : '-1'"
[ngClass]="{ orientation: isOrientation, interactive: isInteractive(), isChecked: isChecked }"
(click)="cardClicked()"
(keyup.enter)="cardClicked()"
(mouseenter)="cardHover()"
>
<div class="left">
<input *ngIf="showRadioButton" type="radio" tabindex="-1" id="{{ structure._id }}" [checked]="isChecked" />
<img alt [src]="'../../../../assets/ico/' + structure?.getTypeStructureIcon() + '.svg'" />
<div class="structureDetails">
......@@ -38,7 +40,6 @@
</div>
<div class="right">
<app-svg-icon *ngIf="!isOrientation" [folder]="'ico'" [icon]="'chevronRight'" [iconClass]="'icon-24'" />
<div *ngIf="isOrientation && !isOrientationRdv">
<app-v3-button
*ngIf="!isSelected"
......@@ -70,5 +71,11 @@
(click)="cardRDV(); $event.stopPropagation()"
/>
</ng-container>
<app-svg-icon
*ngIf="redirectToStructure && !isOrientation"
[folder]="'ico'"
[icon]="'chevronRight'"
[iconClass]="'icon-24'"
/>
</div>
</div>
......@@ -11,21 +11,38 @@
justify-content: space-between;
align-items: center;
transition: all 0.2s ease-in-out;
&:hover {
box-shadow: 0px 12px 24px 0px rgba(0, 0, 0, 0.1);
border-color: $grey-1;
&.interactive {
cursor: pointer;
&:hover {
box-shadow: 0px 12px 24px 0px rgba(0, 0, 0, 0.1);
border-color: $grey-1;
}
}
@media #{$large-phone} {
height: unset;
}
&.interactive {
cursor: pointer;
&.isChecked {
box-shadow: 0px 12px 24px 0px rgba(0, 0, 0, 0.1);
border-color: $red;
&:hover {
border-color: $red;
}
}
.left {
display: flex;
align-items: center;
gap: 24px;
input {
accent-color: $grey-1;
width: 18px;
height: 18px;
margin: 6px;
cursor: pointer;
}
.structureDetails {
display: flex;
flex-direction: column;
......
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Structure } from '../../../models/structure.model';
import { ProfileService } from '../../../profile/services/profile.service';
......@@ -8,17 +8,31 @@ import { ProfileService } from '../../../profile/services/profile.service';
templateUrl: './card.component.html',
styleUrls: ['./card.component.scss'],
})
export class CardComponent {
export class CardComponent implements OnInit {
// The structure element to display
@Input() public structure: Structure;
@Input() public isSelected: boolean;
// If true, click event redirects to profile
@Input() public redirectToStructure = true;
// If true, shows a radio button to select the card, disables the redirection to structure
@Input() public showRadioButton = false;
// If true, checks the radioButton
@Input() public isChecked = false;
// If true, the form comes from the orientation
@Input() public isOrientation = false;
// If in orientation, when we add to list, the card becomes selected
@Input() public isSelected = false;
// If true, the form comes from the orientation and will propose to reserve an appointment
@Input() public isOrientationRdv = false;
@Input() public noDetails = false;
@Input() public isInteractive = true;
@Output() public showDetails: EventEmitter<Structure> = new EventEmitter<Structure>();
@Output() public addToList: EventEmitter<Structure> = new EventEmitter<Structure>();
@Output() public selectRDV: EventEmitter<Structure> = new EventEmitter<Structure>();
@Output() public hover: EventEmitter<Structure> = new EventEmitter<Structure>();
@Output() public showDetails = new EventEmitter<Structure>();
@Output() public hover = new EventEmitter<Structure>();
@Output() public addToList = new EventEmitter<Structure>();
@Output() public selectRDV = new EventEmitter<Structure>();
@Output() public selectedStructure = new EventEmitter<Structure>();
constructor(
private route: ActivatedRoute,
......@@ -26,6 +40,17 @@ export class CardComponent {
public profileService: ProfileService,
) {}
ngOnInit(): void {
if (this.showRadioButton && this.redirectToStructure) {
console.warn("Can't make a card redirect to a structure with a radio button.");
this.redirectToStructure = false;
}
}
isInteractive(): boolean {
return this.showRadioButton || this.redirectToStructure || this.isOrientation;
}
/**
* Display distance in m or km according to value
*/
......@@ -38,20 +63,18 @@ export class CardComponent {
}
public cardClicked(): void {
if (!this.noDetails) {
if (this.redirectToStructure) {
this.showDetails.emit(this.structure);
const queryString = this.route.snapshot.queryParamMap.get('search');
this.router.navigate([], {
relativeTo: this.route,
queryParams: queryString
? {
id: this.structure._id,
search: queryString,
}
: {
id: this.structure._id,
},
queryParams: {
id: this.structure._id,
...(queryString && { search: queryString }),
},
});
} else {
this.selectedStructure.emit(this.structure);
}
}
......
......@@ -268,7 +268,12 @@
<section *ngIf="userIsLoggedIn() && membersWithJobWithPO.length" class="members">
<h2>Accompagnant·es numériques</h2>
<div class="members">
<app-member-card *ngFor="let member of membersWithJobWithPO" [member]="member" />
<app-member-card
*ngFor="let member of membersWithJobWithPO"
[member]="member"
[showContactInfo]="false"
[showEmployer]="false"
/>
</div>
</section>
......@@ -309,10 +314,10 @@
[color]="'red'"
[clickable]="false"
/>
<!-- BaseSkills-->
<div *ngIf="hasBaseSkills()" class="skillsContainer">
<h3 class="titleSkills">Compétences numériques de base</h3>
<ul>
<li *ngFor="let skill of structure.categoriesDisplay.baseSkills" class="details">{{ skill }}</li>
</ul>
......
......@@ -86,7 +86,7 @@ export class StructureListComponent implements OnChanges, OnInit {
}
public isInPrintList(id: string): boolean {
return this.selectedStructureList.findIndex((elem) => elem._id === id) > -1 ? true : false;
return this.selectedStructureList.findIndex((elem) => elem._id === id) > -1;
}
public addStructure(): void {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment