Skip to content

Commit

Permalink
feat(web-office): add general information dashboard
Browse files Browse the repository at this point in the history
ref: MANAGER-16832

Signed-off-by: Guillaume Hyenne <[email protected]>
  • Loading branch information
ghyenne committed Feb 20, 2025
1 parent d4bdf23 commit 1933777
Show file tree
Hide file tree
Showing 33 changed files with 862 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
"common_field_error_maxlength": "Veuillez saisir un maximum de {{maxlength}} caractères.",
"common_field_error_pattern": "Veuillez saisir un format valide.",
"common_office_title": "Mes comptes Microsoft 365",
"general_informations": "Informations générales",
"consumption": "Consommation",
"statistics": "Statistiques",
"licences": "Licences",
"my_offer": "Mon offre",
"license_number": "Nombre de licences",
"common_guides_header": "Consulter nos guides en ligne",
"users": "Utilisateurs",
"users_order_licenses": "Commander plus de licences",
Expand All @@ -21,5 +25,26 @@
"firstname": "Prénom",
"login": "Identifiant",
"form_helper_login_conditions": "Votre identifiant doit contenir entre 3 et 20 caractères. Il peut inclure des lettres, des chiffres et les caractères spéciaux suivants : - _ ",
"form_helper_login_condition_exception": "Il peut également contenir des points, à condition qu'ils soient précédés d'un caractère autorisé et qu'ils ne soient pas suivis d'un autre point."
"form_helper_login_condition_exception": "Il peut également contenir des points, à condition qu'ils soient précédés d'un caractère autorisé et qu'ils ne soient pas suivis d'un autre point.",
"serviceName": "ID du groupe",
"serviceType": "Type de service",
"status": "Statut",
"displayName": "Nom du groupe",
"contacts": "Contacts",
"contact_admin": "Administrateur",
"contact_billing": "Facturation",
"contact_tech": "Technique",
"creation_date": "Date de création",
"renew_date": "Prochaine échéance",
"payAsYouGo": "Paiement à l'utilisation",
"prepaid": "Prépayé",
"noAccountOffer": "Vous ne possedez actuellement aucune licence.",
"manage_contacts": "Gérer les contacts",
"state_ok": "Actif",
"state_autorenewInProgress": "En cours de renouvellement",
"state_expired": "Résilier",
"state_inCreation": "En cours de création",
"state_pendingDebt": "Facture à régler",
"state_unPaid": "Facture impayée",
"error_message": "Votre demande n'a pas pu aboutir. {{ error }}"
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"officeBusiness_serie_name": "Licences Office Business",
"officeProPlus_serie_name": "Licences Office Pro Plus",
"license_number": "Nombre de licences",
"usage_period": "Période",
"usage_period_current": "Le mois en cours",
"usage_period_last": "Le mois dernier",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dashboard_modal_update_headline": "Changer le nom",
"dashboard_modal_update_description": "Veuilliez saisir le nouveau nom que vous souhaitez donner à votre service.",
"dashboard_modal_update_input_label": "Nouveau nom"
}
1 change: 1 addition & 0 deletions packages/manager/apps/web-office/src/api/_mock_/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './order';
export * from './price';
export * from './serviceInfos';
export * from './usageStatistics';
export * from './parentTenant';
16 changes: 16 additions & 0 deletions packages/manager/apps/web-office/src/api/_mock_/parentTenant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { UserStateEnum } from '../api.type';
import { ParentTenantType } from '../parentTenant';

export const parentTenantMock: ParentTenantType = {
address: '123 Main Street',
city: 'Springfield',
creationDate: '2023-05-15',
displayName: 'John Doe',
firstName: 'John',
lastName: 'Doe',
phone: '+1234567890',
serviceName: 'office5678.o365.ovh.com-1234',
serviceType: 'prepaid',
status: UserStateEnum.OK,
zipCode: '12345',
};
13 changes: 12 additions & 1 deletion packages/manager/apps/web-office/src/api/_mock_/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ export const usersMock: UserNativeType[] = [
firstName: 'test',
isVirtual: false,
lastName: 'test',
licences: [LicenseEnum.OFFICE_BUSINESS],
licences: [LicenseEnum.OFFICE_PRO_PLUS],
status: UserStateEnum.OK,
taskPendingId: 0,
usageLocation: 'fr',
},
{
activationEmail: '[email protected]',
deleteAtExpiration: false,
firstName: 'test',
isVirtual: false,
lastName: 'test',
licences: [LicenseEnum.OFFICE_PRO_PLUS],
status: UserStateEnum.OK,
taskPendingId: 0,
usageLocation: 'fr',
Expand Down
8 changes: 5 additions & 3 deletions packages/manager/apps/web-office/src/api/api.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ export enum TaskStatusEnum {
}

export type UserParamsType = {
activationEmail: string;
firstName: string;
lastName: string;
activationEmail?: string;
firstName?: string;
lastName?: string;
displayName?: string;
};

export type UserOrderParamsType = {
domain: string;
firstName: string;
Expand Down
23 changes: 23 additions & 0 deletions packages/manager/apps/web-office/src/api/parentTenant/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { v6 } from '@ovh-ux/manager-core-api';
import { getApiPath } from '../utils/apiPath';
import { ParentTenantType } from './type';

export const getParentTenant = async (
serviceName: string,
): Promise<ParentTenantType> => {
const { data } = await v6.get<ParentTenantType>(
`${getApiPath(serviceName)}parentTenant`,
);
return data;
};

export const putParentTenant = async (
serviceName: string,
parentTenantData: Partial<ParentTenantType>,
): Promise<ParentTenantType> => {
const { data } = await v6.put<ParentTenantType>(
`${getApiPath(serviceName)}parentTenant`,
parentTenantData,
);
return data;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './api';
export * from './key';
export * from './type';
7 changes: 7 additions & 0 deletions packages/manager/apps/web-office/src/api/parentTenant/key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const getOfficeParentTenantQueryKey = (serviceName: string) => [
'get',
'license',
'officePrepaid',
serviceName,
'parentTenant',
];
15 changes: 15 additions & 0 deletions packages/manager/apps/web-office/src/api/parentTenant/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { UserStateEnum } from '../api.type';

export type ParentTenantType = {
address: string;
city: string;
creationDate: string;
displayName: string;
firstName: string;
lastName: string;
phone: string;
serviceName: string;
serviceType: string;
status: UserStateEnum;
zipCode: string;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useTranslation } from 'react-i18next';
import { ODS_BADGE_COLOR, ODS_BADGE_SIZE } from '@ovhcloud/ods-components';
import { OdsBadge } from '@ovhcloud/ods-components/react';
import { StateEnum } from '@/api/serviceInfos';

export type OfficeStateProps = {
size?: ODS_BADGE_SIZE;
state: StateEnum;
} & Record<string, string>;

export const OfficeServiceState = ({ state, ...props }: OfficeStateProps) => {
const { t } = useTranslation('common');

const { size, ...otherProps } = props;

let label = '';
let color: ODS_BADGE_COLOR;

switch (state) {
case StateEnum.Ok:
label = t('state_ok');
color = ODS_BADGE_COLOR.success;
break;
case StateEnum.AutoRenewInProgress:
label = t('state_autorenewInProgress');
color = ODS_BADGE_COLOR.information;
break;
case StateEnum.Expired:
label = t('state_expired');
color = ODS_BADGE_COLOR.critical;
break;
case StateEnum.InCreation:
label = t('state_inCreation');
color = ODS_BADGE_COLOR.information;
break;
case StateEnum.UnPaid:
label = t('state_unPaid');
color = ODS_BADGE_COLOR.critical;
break;
case StateEnum.PendingDebt:
label = t('state_pendingDebt');
color = ODS_BADGE_COLOR.information;
break;
default:
label = state;
color = ODS_BADGE_COLOR.neutral;
break;
}

return (
<OdsBadge
data-testid="badge-status"
size={size || ODS_BADGE_SIZE.md}
color={color}
label={label}
{...otherProps}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';
import { describe, expect } from 'vitest';
import { ODS_BADGE_COLOR } from '@ovhcloud/ods-components';
import { render } from '@/utils/test.provider';
import { OfficeServiceState } from '../OfficeServiceState.component';
import commonTranslation from '@/public/translations/common/Messages_fr_FR.json';

describe('OfficeServiceState component', () => {
it('Badge for ok status', async () => {
const { getByTestId } = render(<OfficeServiceState state={'ok'} />);
const badge = getByTestId('badge-status');

expect(badge).toHaveAttribute('label', commonTranslation.state_ok);

expect(badge).toHaveAttribute('color', ODS_BADGE_COLOR.success);
});

it('Badge for autorenewInProgress status', () => {
const { getByTestId } = render(
<OfficeServiceState state={'autorenewInProgress'} />,
);
const badge = getByTestId('badge-status');

expect(badge).toHaveAttribute(
'label',
commonTranslation.state_autorenewInProgress,
);

expect(badge).toHaveAttribute('color', ODS_BADGE_COLOR.information);
});

it('Badge for expired status', () => {
const { getByTestId } = render(<OfficeServiceState state={'expired'} />);
const badge = getByTestId('badge-status');

expect(badge).toHaveAttribute('label', commonTranslation.state_expired);

expect(badge).toHaveAttribute('color', ODS_BADGE_COLOR.critical);
});

it('Badge for inCreation status', () => {
const { getByTestId } = render(<OfficeServiceState state={'inCreation'} />);
const badge = getByTestId('badge-status');

expect(badge).toHaveAttribute('label', commonTranslation.state_inCreation);

expect(badge).toHaveAttribute('color', ODS_BADGE_COLOR.information);
});

it('Badge for unPaid status', () => {
const { getByTestId } = render(<OfficeServiceState state={'unPaid'} />);
const badge = getByTestId('badge-status');

expect(badge).toHaveAttribute('label', commonTranslation.state_unPaid);

expect(badge).toHaveAttribute('color', ODS_BADGE_COLOR.critical);
});

it('Badge for pendingDebt status', () => {
const { getByTestId } = render(
<OfficeServiceState state={'pendingDebt'} />,
);
const badge = getByTestId('badge-status');

expect(badge).toHaveAttribute('label', commonTranslation.state_pendingDebt);

expect(badge).toHaveAttribute('color', ODS_BADGE_COLOR.information);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { vi, describe, expect } from 'vitest';
import '@testing-library/jest-dom';
import { renderHook, waitFor } from '@testing-library/react';
import { useParams } from 'react-router-dom';
import {
parentTenantMock,
licensesMock,
licensesPrepaidMock,
} from '@/api/_mock_';
import { useOfficeParentTenant } from '@/hooks';
import { wrapper } from '@/utils/test.provider';

describe('useOfficeParentTenant', () => {
it('should return the detail of parentTenant if prepaid', async () => {
vi.mocked(useParams).mockReturnValue({
serviceName: licensesPrepaidMock[0],
});

const { result } = renderHook(() => useOfficeParentTenant(), {
wrapper,
});
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(result.current.data).toEqual(parentTenantMock);
});

it('should return the detail of current license if payAsYouGo', async () => {
vi.mocked(useParams).mockReturnValue({
serviceName: licensesMock[0].serviceName,
});
const { result } = renderHook(() => useOfficeParentTenant(), {
wrapper,
});
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(result.current.data).toEqual(licensesMock[0]);
});
});
1 change: 1 addition & 0 deletions packages/manager/apps/web-office/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './useOfficeUsers';
export * from './useOfficeUserDetail';
export * from './useOrderCatalog';
export * from './useDateFnsLocale';
export * from './useOfficeParentTenant';
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useQuery } from '@tanstack/react-query';
import { useParams } from 'react-router-dom';
import { useOfficeServiceType } from './useOfficeServiceType';
import {
getParentTenant,
getOfficeParentTenantQueryKey,
} from '@/api/parentTenant';
import {
getOfficeLicenseDetailsQueryKey,
getOfficeLicenseDetails,
} from '@/api/license';

export const useOfficeParentTenant = () => {
const { serviceName } = useParams();
const serviceType = useOfficeServiceType(serviceName);
const isPrepaid = serviceType === 'prepaid';

return useQuery({
queryKey: [
isPrepaid
? getOfficeParentTenantQueryKey(serviceName)
: getOfficeLicenseDetailsQueryKey(serviceName),
],
queryFn: isPrepaid
? () => getParentTenant(serviceName)
: () => getOfficeLicenseDetails(serviceName),
});
};
10 changes: 7 additions & 3 deletions packages/manager/apps/web-office/src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ html {
font-family: var(--ods-font-family-default);
}

ods-button.action-menu-item::part(button) {
width: 100%;
justify-content: left;
.menu-item-button {
&::part(button) {
width: 100%;
justify-content: left;
height: 32px;
border-radius: 0;
}
}

ods-modal.max-height-modal::part(dialog) {
Expand Down
1 change: 0 additions & 1 deletion packages/manager/apps/web-office/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
initI18n,
} from '@ovh-ux/manager-react-shell-client';
import App from './App';
import '@ovhcloud/ods-themes/default';
import './index.scss';
import './vite-hmr';
import { UNIVERSE, SUB_UNIVERSE, APP_NAME, LEVEL2 } from './tracking.constants';
Expand Down
Loading

0 comments on commit 1933777

Please sign in to comment.