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

src/components: add component ProfileCoordinatorContact to display a notice in ProfileDetails #547

Merged
merged 9 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions public/icons/profile_coordinator_contact/icons.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/svg/profile-placeholder.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
154 changes: 154 additions & 0 deletions src/components/__tests__/ProfileCoordinatorContact.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { colors } from 'quasar';
import ProfileCoordinatorContact from 'components/profile/ProfileCoordinatorContact.vue';
import { i18n } from '../../boot/i18n';
import { rideToWorkByBikeConfig } from 'src/boot/global_vars';

// colors
const { getPaletteColor } = colors;
const grey10 = getPaletteColor('grey-10');

// selectors
const classSelectorIcon = '.q-icon';
const selectorProfileCoordinatorContact = 'profile-coordinator-contact';
const selectorContactMessage = 'contact-message';
const selectorAvatar = 'coordinator-avatar';
const selectorName = 'coordinator-name';
const selectorPhone = 'coordinator-phone';
const selectorEmail = 'coordinator-email';

// constants
const avatarSize = '56px';
const componentPaddingSm = '16px';
const componentPaddingLg = '24px';
const iconSize = '18px';
const nameFontSize = '14px';
const nameFontWeight = '700';
const textFontSize = '14px';
const textFontWeight = '400';

describe('<ProfileCoordinatorContact>', () => {
it('has translation for all strings', () => {
cy.testLanguageStringsInContext(
['textCoordinatorContact'],
'profile',
i18n,
);
});

let coordinator;

before(() => {
cy.fixture('companyCoordinator').then((companyCoordinator) => {
coordinator = companyCoordinator;
});
});

context('desktop', () => {
beforeEach(() => {
cy.mount(ProfileCoordinatorContact, {
props: {},
});
cy.viewport('macbook-16');
});

coreTests();

it('renders component padding', () => {
cy.dataCy(selectorProfileCoordinatorContact).should(
'have.css',
'padding',
componentPaddingLg,
);
});
});

context('mobile', () => {
beforeEach(() => {
cy.mount(ProfileCoordinatorContact, {
props: {},
});
cy.viewport('iphone-6');
});

coreTests();

it('renders component padding', () => {
cy.dataCy(selectorProfileCoordinatorContact).should(
'have.css',
'padding',
componentPaddingSm,
);
});
});

function coreTests() {
it('renders component', () => {
cy.dataCy(selectorProfileCoordinatorContact).should('be.visible');
});

it('root element has borderRadius', () => {
cy.dataCy(selectorProfileCoordinatorContact).should(
'have.css',
'border-radius',
rideToWorkByBikeConfig.borderRadiusCard,
);
});

it('renders company coordinator contact message', () => {
cy.dataCy(selectorContactMessage)
.should('be.visible')
.then(($el) => {
const content = $el.text();
cy.stripHtmlTags(
i18n.global.t('profile.textCoordinatorContact'),
).then((text) => {
expect(content).to.equal(text);
});
});
});

it('renders avatar of a company coordinator', () => {
cy.dataCy(selectorAvatar)
.should('be.visible')
.and('have.css', 'width', avatarSize)
.and('have.css', 'height', avatarSize);
cy.matchImageSnapshotNamed(
selectorAvatar,
`${Cypress.currentTest.titlePath[0]}-avatar`,
);
});

it('renders name of a coordinator', () => {
cy.dataCy(selectorName)
.should('be.visible')
.and('have.css', 'font-size', nameFontSize)
.and('have.css', 'font-weight', nameFontWeight)
.and('have.color', grey10)
.and('contain', coordinator.name);
});

it('renders phone number with a phone icon', () => {
cy.dataCy(selectorPhone)
.should('be.visible')
.and('have.css', 'font-size', textFontSize)
.and('have.css', 'font-weight', textFontWeight)
.and('have.color', grey10)
.and('contain', coordinator.phone)
.find(classSelectorIcon)
.should('have.css', 'width', iconSize)
.and('have.css', 'height', iconSize);
});

it('renders email with an email icon', () => {
cy.dataCy(selectorEmail)
.should('be.visible')
.and('have.css', 'font-size', textFontSize)
.and('have.css', 'font-weight', textFontWeight)
.and('have.color', grey10)
.and('contain', coordinator.email)
.find(classSelectorIcon)
.should('have.css', 'width', iconSize)
.and('have.css', 'height', iconSize);
});
}
});
3 changes: 3 additions & 0 deletions src/components/__tests__/ProfileDetails.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const selectorPackageLink = 'profile-details-package-link';
const selectorPaymentState = 'profile-details-payment-state';
const selectorPersonalDetails = 'profile-details';
const selectorPhone = 'profile-details-phone';
const selectorProfileCoordinatorContact = 'profile-coordinator-contact';
const selectorSize = 'profile-details-size';
const selectorState = 'profile-details-state';
const selectorTeam = 'profile-details-team';
Expand Down Expand Up @@ -238,6 +239,8 @@ function coreTests() {
cy.dataCy(selectorPhone)
.find(dataSelectorValue)
.should('contain', formPersonalDetails.phone);
// coordinator contact
cy.dataCy(selectorProfileCoordinatorContact).should('be.visible');
});
});

Expand Down
105 changes: 105 additions & 0 deletions src/components/profile/ProfileCoordinatorContact.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<script lang="ts">
/**
* ProfileCoordinatorContact Component
*
* @description * Use this component to display a card with contact
* instructions.
*
* Used in `ProfileDetails` component.
*
* @example
* <profile-coordinator-contact />
*
* @see [Figma Design](https://www.figma.com/design/L8dVREySVXxh3X12TcFDdR/Do-pr%C3%A1ce-na-kole?node-id=4858-104393&t=WcrxMvLONggUrjGt-1)
*/

// libraries
import { defineComponent } from 'vue';
import { ProfileCoordinator } from '../../types/Profile';
import { rideToWorkByBikeConfig } from '../../boot/global_vars';

// fixtures
import companyCoordinator from '../../../test/cypress/fixtures/companyCoordinator.json';

export default defineComponent({
name: 'ProfileCoordinatorContact',
setup() {
const coordinator = companyCoordinator as ProfileCoordinator;

const avatarSize = '56px';
const iconSize = '18px';

const borderRadius = rideToWorkByBikeConfig.borderRadiusCard;
const borderColor = rideToWorkByBikeConfig.colorGray;

return {
avatarSize,
coordinator,
borderColor,
borderRadius,
iconSize,
};
},
});
</script>

<template>
<div
v-if="coordinator"
class="text-grey-10"
:class="[$q.screen.gt.sm ? 'q-pa-lg' : 'q-pa-md']"
data-cy="profile-coordinator-contact"
:style="{ border: `1px solid ${borderColor}`, borderRadius }"
>
<div>
<div
data-cy="contact-message"
v-html="$t('profile.textCoordinatorContact')"
/>
</div>
<div class="flex items-center gap-12 q-mt-md">
<q-avatar data-cy="coordinator-avatar" :size="avatarSize">
<q-img
ratio="1"
:src="coordinator.image.src"
placeholder-src="~assets/svg/profile-placeholder.svg"
:alt="coordinator.name"
/>
</q-avatar>
<div>
<div data-cy="coordinator-name" class="text-weight-bold q-mt-sm">
{{ coordinator.name }}
</div>
<div
class="flex items-center gap-8 gap-x-24 q-mt-sm"
data-cy="coordinator-contact"
>
<a
:href="`tel:${coordinator.phone}`"
class="text-grey-10"
data-cy="coordinator-phone"
>
<q-icon
name="svguse:icons/profile_coordinator_contact/icons.svg#phone"
color="primary"
:size="iconSize"
/>
{{ coordinator.phone }}
</a>
<a
:href="`mailto:${coordinator.email}`"
class="text-grey-10"
data-cy="coordinator-email"
>
<q-icon
name="svguse:icons/profile_coordinator_contact/icons.svg#email"
color="primary"
:size="iconSize"
/>
{{ coordinator.email }}
</a>
</div>
</div>
</div>
</div>
</template>
8 changes: 8 additions & 0 deletions src/components/profile/ProfileDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import FormUpdateEmail from '../form/FormUpdateEmail.vue';
import FormUpdateGender from '../form/FormUpdateGender.vue';
import FormUpdateNickname from '../form/FormUpdateNickname.vue';
import LanguageSwitcher from '../global/LanguageSwitcher.vue';
import ProfileCoordinatorContact from './ProfileCoordinatorContact.vue';

// composables
import { i18n } from '../../boot/i18n';
Expand All @@ -52,6 +53,7 @@ export default defineComponent({
FormUpdateGender,
FormUpdateNickname,
LanguageSwitcher,
ProfileCoordinatorContact,
},
setup() {
const iconSize = '18px';
Expand Down Expand Up @@ -353,5 +355,11 @@ export default defineComponent({
</div>
</div>
</div>

<!-- Coordinator contact -->
<profile-coordinator-contact
class="q-mt-xl"
data-cy="profile-coordinator-contact"
/>
</div>
</template>
7 changes: 7 additions & 0 deletions src/components/types/Profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,10 @@ export interface Profile {
deliveryAddress: FormCompanyAddressFields;
paymentState: PaymentState;
}

export interface ProfileCoordinator {
name: string;
avatar: string;
phone: string;
email: string;
}
4 changes: 4 additions & 0 deletions src/css/utility.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
row-gap: 8px;
}

.gap-x-24 {
column-gap: 24px;
}

.gap-x-32 {
column-gap: 32px;
}
Expand Down
1 change: 1 addition & 0 deletions src/i18n/cs.toml
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ tabDetails = "Vaše údaje"
tabForms = "Dotazníky"
tabNewsletter = "Newsletter"
tabNotifications = "Historie notifikací"
textCoordinatorContact = "S otázkami a připomínkami ohledně startovních balíčků, schvalování platby za startovné, vnitrofiremních akcí a výzev se můžete obrátit na <b>vašeho firemního koordinátora/vaši firemní koordinátorku:</b>"
textPasswordConfirm = "Změnu e-mailu je potřeba potvrdit heslem do Do práce na kole:"
titleChallengeDetails = "Soutěžní údaje"
titlePersonalDetails = "Osobní údaje"
Expand Down
1 change: 1 addition & 0 deletions src/i18n/en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ tabDetails = "Your data"
tabForms = "Questionnaires"
tabNewsletter = "Newsletter"
tabNotifications = "Notification history"
textCoordinatorContact = "You can contact <b>your company coordinator</b> with questions and comments about entry packages, entry fee approval, in-company events and challenges:"
textPasswordConfirm = "You need to confirm the email change with the password to Ride to Work by Bike:"
titleChallengeDetails = "Competition Details"
titlePersonalDetails = "Personal Details"
Expand Down
1 change: 1 addition & 0 deletions src/i18n/sk.toml
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ tabDetails = "Vaše údaje"
tabForms = "Dotazníky"
tabNewsletter = "Newsletter"
tabNotifications = "História oznámení"
textCoordinatorContact = "V prípade otázok a pripomienok týkajúcich sa vstupných balíkov, schvaľovania vstupných poplatkov, interných podujatí a výziev sa obráťte na <b>svojho firemného koordinátora:</b>"
textPasswordConfirm = "Musíte potvrdiť zmenu e-mailu s heslom do aplikácie Do práce na bicykli:"
titleChallengeDetails = "Súťažné údaje"
titlePersonalDetails = "Osobné údaje"
Expand Down
9 changes: 9 additions & 0 deletions test/cypress/fixtures/companyCoordinator.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "Lucie Svobodová",
"image": {
"src": "https://picsum.photos/id/40/300/300",
"alt": "Lucie Svobodová"
},
"phone": "(+420) 123 456 789",
"email": "[email protected]"
}
Loading