Skip to content

feat(web-domain-reseller): tabs#22129

Open
louisbensiovh wants to merge 1 commit intofeat/DCE-148from
feat/DCE-167
Open

feat(web-domain-reseller): tabs#22129
louisbensiovh wants to merge 1 commit intofeat/DCE-148from
feat/DCE-167

Conversation

@louisbensiovh
Copy link

ref: #DCE-167

@louisbensiovh louisbensiovh requested a review from a team as a code owner February 6, 2026 10:37
@louisbensiovh louisbensiovh requested review from SBrendan, Copilot, kb-ovh and nfoufeovh and removed request for a team February 6, 2026 10:37
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a tabbed navigation interface for the domain reseller feature, refactoring the dashboard into separate tabs for information and domain list views.

Changes:

  • Restructured the domain reseller dashboard to use a tab-based layout with two tabs: general information and domains list
  • Extracted dashboard content into a separate DomainResellerInformations component
  • Added routing configuration for tab navigation with automatic redirect to the information tab

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
routes.tsx Updated routing structure to support nested tab routes with default redirect
routes.constants.ts Added URL constants for the information and list tab routes
DomainsList.tsx Created placeholder component for the domains list tab
DomainResellerInformations.tsx Extracted dashboard content into dedicated informations tab component
DomainResellerDashboard.tsx Refactored to render tabs and outlet instead of direct content
DomainResellerDashboard.spec.tsx Removed obsolete tests that covered moved functionality
constants.ts Defined tab configuration with IDs, names, and values
DomainResellerTabs.tsx Implemented tab component with navigation logic
DomainResellerTabs.spec.tsx Added tests for the tabs component
utils.ts Added getDataFromEnvironment utility function
Messages_fr_FR.json Added French translation for the domains tab label
Comments suppressed due to low confidence (1)

packages/manager/apps/web-domains/src/common/utils/utils.ts:1

  • React hooks like useContext cannot be called directly from utility functions. This function will fail when called outside a React component context. Convert this to a custom hook by renaming it to useDataFromEnvironment or refactor the calling code to pass the context data as parameters.
import { TServiceInfo } from '@/common/types/common.types';

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

});

describe('DomainResellerDashboard', () => {
beforeEach(() => {
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The beforeEach hook is defined but contains no implementation. This test file has been significantly reduced and no longer provides adequate coverage for the dashboard component's new tab integration behavior.

Copilot uses AI. Check for mistakes.
ref: #DCE-167

Signed-off-by: Louis BENSI <louis.bensi@corp.ovh.com>
@ovh ovh deleted a comment from Copilot AI Feb 9, 2026
@louisbensiovh louisbensiovh requested a review from Copilot February 9, 2026 09:23
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -1,55 +1,6 @@
import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { describe, it, expect, vi } from 'vitest';
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beforeEach is used but no longer imported from vitest, which will cause the test file to crash at runtime. Add beforeEach back to the vitest import or remove the beforeEach usage.

Suggested change
import { describe, it, expect, vi } from 'vitest';
import { beforeEach, describe, it, expect, vi } from 'vitest';

Copilot uses AI. Check for mistakes.
/>
</div>
</section>
<BaseLayout header={header} tabs={DomainResellerTabs()}>
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing DomainResellerTabs() calls a React component as a plain function even though it uses hooks (useState, useEffect, useNavigate, etc.). This breaks the Rules of Hooks and can lead to state being attached to the wrong component. Pass it as a React element instead (e.g., tabs={<DomainResellerTabs />}) or as a component reference if BaseLayout expects that.

Suggested change
<BaseLayout header={header} tabs={DomainResellerTabs()}>
<BaseLayout header={header} tabs={<DomainResellerTabs />}>

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +24
export const getDataFromEnvironment = () => {
const context = useContext(ShellContext);
const { ovhSubsidiary } = context.environment.getUser();
const region = context.environment.getRegion();

return { region, ovhSubsidiary };
};
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getDataFromEnvironment calls useContext, so it should be implemented as a custom hook (and named accordingly, e.g. useEnvironmentData) to comply with hook conventions and avoid accidental usage outside React render. Consider moving it to a hooks module to prevent non-React callers from importing it as a generic utility.

Suggested change
export const getDataFromEnvironment = () => {
const context = useContext(ShellContext);
const { ovhSubsidiary } = context.environment.getUser();
const region = context.environment.getRegion();
return { region, ovhSubsidiary };
};
export const useEnvironmentData = () => {
const context = useContext(ShellContext);
const { ovhSubsidiary } = context.environment.getUser();
const region = context.environment.getRegion();
return { region, ovhSubsidiary };
};
export const getDataFromEnvironment = () => {
return useEnvironmentData();
};

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use hook here

Comment on lines +14 to +30
useEffect(() => {
const currentTab = DomainResellerTabsProps.find((tab) =>
location.pathname.includes(tab.value),
);
if (currentTab) {
setValue(currentTab.value);
}
}, [location.pathname]);

const handleValueChange = (event: TabsValueChangeEvent) => {
const selectedTab = DomainResellerTabsProps.find(
(tab) => tab.value === event.value,
);
if (selectedTab) {
navigate(selectedTab.value, { replace: true });
}
};
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tab selection is inferred via includes(tab.value) and navigation uses a relative navigate(selectedTab.value), while route constants are absolute (e.g. /domain-reseller/information). This makes routing brittle (substring collisions and ambiguity about relative resolution). Prefer matching via router helpers (e.g. matchPath) and navigate using the canonical URL constants (or explicit relative paths tied to the parent route).

Copilot uses AI. Check for mistakes.
import { DashboardTabItemProps } from '@/domain/types/serviceDetail';
import { NAMESPACES } from '@ovh-ux/manager-common-translations';

export const DomainResellerTabsProps: DashboardTabItemProps[] = [
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DomainResellerTabsProps is a configuration array, not React props. Renaming it to something like domainResellerTabs, domainResellerTabItems, or domainResellerTabsConfig would make its purpose clearer.

Suggested change
export const DomainResellerTabsProps: DashboardTabItemProps[] = [
export const domainResellerTabsConfig: DashboardTabItemProps[] = [

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +2
export default function DomainResellerDomainsList() {
return 'List des domaines';
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tab returns a hard-coded French string. Prefer returning JSX and sourcing the label from i18n translations (consistent with the rest of the feature), e.g. via useTranslation('domain-reseller') and a translation key.

Suggested change
export default function DomainResellerDomainsList() {
return 'List des domaines';
import { useTranslation } from 'react-i18next';
export default function DomainResellerDomainsList() {
const { t } = useTranslation('domain-reseller');
return <>{t('domainsList.tabLabel')}</>;

Copilot uses AI. Check for mistakes.
Comment on lines 10 to 12
import { useGetDomainsList } from '@/domain-reseller/hooks/data/query';
import Loading from '@/domain/components/Loading/Loading';
import { getOrderURL } from '@ovh-ux/manager-module-order';
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the refactor to a layout + <Outlet />, these imports appear unused in this file. If they’re no longer needed, remove them to keep the module focused and avoid lint/test failures in stricter configs.

Copilot uses AI. Check for mistakes.
Comment on lines 16 to 18
render(<DomainResellerDashboard />);
expect(screen.getByText('domain_reseller_title')).toBeInTheDocument();
});
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dashboard is now primarily a layout wrapper that wires tabs + <Outlet />, but the test suite only checks the title. Add coverage asserting that the tabs are rendered/passed into BaseLayout, and that routed child content renders via the outlet (at least one happy-path route).

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +24
export const getDataFromEnvironment = () => {
const context = useContext(ShellContext);
const { ovhSubsidiary } = context.environment.getUser();
const region = context.environment.getRegion();

return { region, ovhSubsidiary };
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use hook here

const navigate = useNavigate();
const [value, setValue] = useState('information');

useEffect(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please see ongoing operation implementation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants