maruyama.t f265d0ff45 Merged PR 812: 「oderLicense」や「CardLicense」を開いて閉じるとパンくずリストがおかしくなる
## 概要
[Task3771: 対応](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3771)

ポップアップを×で閉じた際に、パンくずリストを保持したまま、`dispatch(getMyAccountAsync()`しており画面を初期化していた。
画面を更新するのかしないのかあいまいな挙動になっていた。

対応としては、他のポップアップと同様、×で閉じた場合は画面は更新しないように修正。
追加でパンくずリストを初期化する処理を作成し、ポップアップ側でAPIを呼び出した場合のみそれを実行する。

## レビューポイント
- 特筆する点はなし

## UIの変更
- スクショ置き場
https://ndstokyo.sharepoint.com/:f:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88/Task3771?csf=1&web=1&e=USf40m

## 動作確認状況
- ローカルで確認

## 補足
- 相談、参考資料などがあれば
2024-03-07 10:41:30 +00:00

549 lines
20 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useCallback, useState, useEffect } from "react";
import Footer from "components/footer";
import Header from "components/header";
import styles from "styles/app.module.scss";
import { UpdateTokenTimer } from "components/auth/updateTokenTimer";
import { useDispatch, useSelector } from "react-redux";
import { AppDispatch } from "app/store";
import { getTranslationID } from "translation";
import { useTranslation } from "react-i18next";
import { PartnerLicenseInfo } from "api";
import { CardLicenseIssuePopup } from "./cardLicenseIssuePopup";
import postAdd from "../../assets/images/post_add.svg";
import history from "../../assets/images/history.svg";
import returnLabel from "../../assets/images/undo.svg";
import { isApproveTier } from "../../features/auth/utils";
import { TIERS } from "../../components/auth/constants";
import {
getPartnerLicenseAsync,
ACCOUNTS_VIEW_LIMIT,
selectMyAccountInfo,
selectTotal,
selectOwnPartnerLicense,
selectChildrenPartnerLicenses,
selectHierarchicalElements,
selectTotalPage,
selectIsLoading,
selectOffset,
selectCurrentPage,
pushHierarchicalElement,
popHierarchicalElement,
spliceHierarchicalElement,
savePageInfo,
getMyAccountAsync,
changeSelectedRow,
} from "../../features/license/partnerLicense";
import { LicenseOrderPopup } from "./licenseOrderPopup";
import { LicenseOrderHistory } from "./licenseOrderHistory";
import { LicenseSummary } from "./licenseSummary";
import progress_activit from "../../assets/images/progress_activit.svg";
const PartnerLicense: React.FC = (): JSX.Element => {
const dispatch: AppDispatch = useDispatch();
const [t] = useTranslation();
// popup制御関係
const [isCardLicenseIssuePopupOpen, setIsCardLicenseIssuePopupOpen] =
useState(false);
const [islicenseOrderPopupOpen, setIslicenseOrderPopupOpen] = useState(false);
const [islicenseOrderHistoryOpen, setIslicenseOrderHistoryOpen] =
useState(false);
const [isViewDetailsOpen, setIsViewDetailsOpen] = useState(false);
// 階層表示用
const tierNames: { [key: number]: string } = {
// eslint-disable-next-line @typescript-eslint/naming-convention
1: t(getTranslationID("common.label.tier1")),
// eslint-disable-next-line @typescript-eslint/naming-convention
2: t(getTranslationID("common.label.tier2")),
// eslint-disable-next-line @typescript-eslint/naming-convention
3: t(getTranslationID("common.label.tier3")),
// eslint-disable-next-line @typescript-eslint/naming-convention
4: t(getTranslationID("common.label.tier4")),
// eslint-disable-next-line @typescript-eslint/naming-convention
5: t(getTranslationID("common.label.tier5")),
};
const onlicenseIssueOpen = useCallback(() => {
setIsCardLicenseIssuePopupOpen(true);
}, [setIsCardLicenseIssuePopupOpen]);
const onlicenseOrderOpen = useCallback(() => {
setIslicenseOrderPopupOpen(true);
}, [setIslicenseOrderPopupOpen]);
// apiからの値取得関係
const myAccountInfo = useSelector(selectMyAccountInfo);
const total = useSelector(selectTotal);
const totalPage = useSelector(selectTotalPage);
const ownPartnerLicenseInfo = useSelector(selectOwnPartnerLicense);
const childrenPartnerLicensesInfo = useSelector(
selectChildrenPartnerLicenses
);
const hierarchicalElements = useSelector(selectHierarchicalElements);
const isLoading = useSelector(selectIsLoading);
// ページネーション制御用
const currentPage = useSelector(selectCurrentPage);
const offset = useSelector(selectOffset);
// ページネーションのボタンクリック時のアクション
const movePage = (targetOffset: number) => {
dispatch(
savePageInfo({ limit: ACCOUNTS_VIEW_LIMIT, offset: targetOffset })
);
};
// パンくずリスト内のアカウント押下時
const onClickBreadCrumbList = (id: number) => {
const clickLevel = hierarchicalElements.findIndex(
(param) => param.accountId === id
);
const nowLevel = hierarchicalElements.length - 1;
const deleteCount = nowLevel - clickLevel;
// 階層を上がった分だけ表示アカウント管理用の配列の最後からパラメータを削除する
if (deleteCount > 0) {
dispatch(spliceHierarchicalElement({ deleteCount }));
movePage(0);
}
};
// 行要素クリック時イベント
const handleRowClick = (value: PartnerLicenseInfo) => {
dispatch(
pushHierarchicalElement({
hierarchicalElement: {
accountId: value.accountId,
companyName: value.companyName,
},
})
);
movePage(0);
};
// returnボタンクリック時イベント
const returnClick = () => {
dispatch(popHierarchicalElement());
movePage(0);
};
// ログイン時に階層をチェック
const isTier1 = isApproveTier([TIERS.TIER1]);
const isTier2ToTier4 = isApproveTier([TIERS.TIER2, TIERS.TIER3, TIERS.TIER4]);
// viewDetailsボタン押下時
const onClickViewDetails = useCallback(
(value?: PartnerLicenseInfo) => {
dispatch(changeSelectedRow({ value }));
setIsViewDetailsOpen(true);
},
[dispatch, setIsViewDetailsOpen]
);
// orderHistoryボタン押下時
const onClickOrderHistory = useCallback(
(value?: PartnerLicenseInfo) => {
dispatch(changeSelectedRow({ value }));
setIslicenseOrderHistoryOpen(true);
},
[dispatch, setIslicenseOrderHistoryOpen]
);
// マウント時のみ実行
useEffect(() => {
dispatch(getMyAccountAsync());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// 自アカウントID取得時に実行
useEffect(() => {
if (myAccountInfo.accountId !== 0) {
dispatch(
getPartnerLicenseAsync({
limit: ACCOUNTS_VIEW_LIMIT,
offset,
accountId: myAccountInfo.accountId,
})
);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [myAccountInfo]);
// 現在の表示階層に合わせたボタン制御用
const [buttonLabel, setButtonLabel] = useState("");
// パンくずリスト用stateに自アカウントを追加
useEffect(() => {
if (
hierarchicalElements.length === 0 &&
ownPartnerLicenseInfo.accountId !== 0
) {
dispatch(
pushHierarchicalElement({
hierarchicalElement: {
accountId: ownPartnerLicenseInfo.accountId,
companyName: ownPartnerLicenseInfo.companyName,
},
})
);
}
// 表内のボタン表示判定
if (hierarchicalElements.length === 1 && ownPartnerLicenseInfo.tier !== 4) {
setButtonLabel(
t(getTranslationID("partnerLicense.label.orderHistoryButton"))
);
} else if (ownPartnerLicenseInfo.tier === 4) {
setButtonLabel(t(getTranslationID("partnerLicense.label.viewDetails")));
} else {
setButtonLabel("");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ownPartnerLicenseInfo]);
// 表内の情報取得処理
useEffect(() => {
if (hierarchicalElements.length !== 0) {
dispatch(
getPartnerLicenseAsync({
limit: ACCOUNTS_VIEW_LIMIT,
offset,
accountId:
hierarchicalElements[hierarchicalElements.length - 1].accountId,
})
);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hierarchicalElements, currentPage]);
return (
<>
{/* isPopupOpenがfalseの場合はポップアップのhtmlを生成しないように対応。これによりポップアップは都度生成されて初期化の考慮が減る */}
{isCardLicenseIssuePopupOpen && (
<CardLicenseIssuePopup
onClose={() => {
setIsCardLicenseIssuePopupOpen(false);
}}
/>
)}
{islicenseOrderPopupOpen && (
<LicenseOrderPopup
onClose={() => {
setIslicenseOrderPopupOpen(false);
}}
/>
)}
{islicenseOrderHistoryOpen && (
<LicenseOrderHistory
onReturn={() => {
setIslicenseOrderHistoryOpen(false);
}}
/>
)}
{isViewDetailsOpen && (
<LicenseSummary
onReturn={() => {
setIsViewDetailsOpen(false);
}}
/>
)}
{!islicenseOrderHistoryOpen && !isViewDetailsOpen && (
<div className={styles.wrap}>
<Header />
<UpdateTokenTimer />
<main className={styles.main}>
<div className="">
<div className={styles.pageHeader}>
<h1 className={styles.pageTitle}>
{t(getTranslationID("partnerLicense.label.title"))}
</h1>
</div>
</div>
<section className={styles.license}>
<div>
<h2>{t(getTranslationID("partnerLicense.label.subTitle"))}</h2>
<ul className={styles.menuAction}>
<li>
{hierarchicalElements.length > 1 && (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<a
className={`${styles.menuLink} ${styles.isActive}`}
onClick={returnClick}
>
<img
src={returnLabel}
alt=""
className={styles.menuIcon}
/>
{t(getTranslationID("common.label.return"))}
</a>
)}
</li>
<li>
{isTier2ToTier4 && (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<a
className={`${styles.menuLink} ${styles.isActive}`}
onClick={onlicenseOrderOpen}
>
<img src={postAdd} alt="" className={styles.menuIcon} />
{t(
getTranslationID(
"partnerLicense.label.orderLicenseButton"
)
)}
</a>
)}
</li>
<li>
{isTier2ToTier4 && (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<a
className={`${styles.menuLink} ${styles.isActive}`}
onClick={() => {
onClickOrderHistory();
}}
>
<img src={history} alt="" className={styles.menuIcon} />
{t(
getTranslationID(
"partnerLicense.label.orderHistoryButton"
)
)}
</a>
)}
</li>
{/* 第1階層 */}
<li>
{isTier1 && (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<a
className={`${styles.menuLink} ${styles.isActive}`}
onClick={onlicenseIssueOpen}
>
<img src={postAdd} alt="" className={styles.menuIcon} />
{t(
getTranslationID(
"partnerLicense.label.IssueLicenseCardButton"
)
)}
</a>
)}
</li>
</ul>
<ul className={styles.brCrumbLicense}>
{hierarchicalElements.map((value) => (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
<li
key={value.accountId}
onClick={() => {
onClickBreadCrumbList(value.accountId);
}}
>
<a>{value.companyName}</a>
</li>
))}
</ul>
<table className={`${styles.table} ${styles.partner}`}>
<tr className={styles.tableHeader}>
<th>{t(getTranslationID("partnerLicense.label.name"))}</th>
<th>
{t(getTranslationID("partnerLicense.label.category"))}
</th>
<th>
{t(getTranslationID("partnerLicense.label.accountId"))}
</th>
<th>
{t(getTranslationID("partnerLicense.label.stockLicense"))}
</th>
<th>
{t(
getTranslationID("partnerLicense.label.issueRequested")
)}
</th>
<th>
{t(getTranslationID("partnerLicense.label.shortage"))}
</th>
<th className={styles.noLine}>
{t(
getTranslationID("partnerLicense.label.issueRequesting")
)}
</th>
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
<th />
</tr>
<tr className={styles.isOpen}>
<td>{ownPartnerLicenseInfo.companyName}</td>
<td>{tierNames[ownPartnerLicenseInfo.tier]}</td>
<td>{ownPartnerLicenseInfo.accountId}</td>
<td>
{ownPartnerLicenseInfo.tier !== 1
? ownPartnerLicenseInfo.stockLicense
: "-"}
</td>
<td>{ownPartnerLicenseInfo.issuedRequested}</td>
<td>
<span
className={
ownPartnerLicenseInfo.shortage > 0 &&
ownPartnerLicenseInfo.tier !== 1
? styles.isAlert
: ""
}
>
{ownPartnerLicenseInfo.tier !== 1
? ownPartnerLicenseInfo.shortage
: "-"}
</span>
</td>
<td>
{ownPartnerLicenseInfo.tier !== 1
? ownPartnerLicenseInfo.issueRequesting
: "-"}
</td>
<td>
<ul
className={`${styles.menuAction} ${styles.menuInTable}`}
>
<li>{/* レイアウト維持用 */}</li>
</ul>
</td>
</tr>
{childrenPartnerLicensesInfo.map((value) => (
<tr key={value.accountId}>
<td
title={value.tier !== 5 ? "View child accounts" : ""}
onClick={() => {
if (value.tier !== 5) {
handleRowClick(value);
}
}}
>
{value.companyName}
</td>
<td>{tierNames[value.tier]}</td>
<td>{value.accountId}</td>
<td>{value.stockLicense}</td>
<td>{value.issuedRequested}</td>
<td>
<span
className={value.shortage > 0 ? styles.isAlert : ""}
>
{value.shortage}
</span>
</td>
<td>{value.issueRequesting}</td>
<td>
<ul
className={`${styles.menuAction} ${styles.inTable}`}
>
<li>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<a
className={`${styles.menuLink} ${
buttonLabel ? styles.isActive : ""
}`}
onClick={() => {
if (ownPartnerLicenseInfo.tier === 4) {
onClickViewDetails(value);
} else {
onClickOrderHistory(value);
}
}}
>
{buttonLabel}
</a>
</li>
</ul>
</td>
</tr>
))}
</table>
{!isLoading && childrenPartnerLicensesInfo.length === 0 && (
<p
style={{
margin: "10px",
textAlign: "center",
}}
>
{t(getTranslationID("common.message.listEmpty"))}
</p>
)}
{/* pagenation */}
<div className={styles.pagenation}>
<nav className={styles.pagenationNav}>
<span className={styles.pagenationTotal}>
{total}{" "}
{t(getTranslationID("partnerLicense.label.accounts"))}
</span>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<a
onClick={() => {
movePage(0);
}}
className={` ${
!isLoading && currentPage !== 1 ? styles.isActive : ""
}`}
>
«
</a>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<a
onClick={() => {
movePage((currentPage - 2) * ACCOUNTS_VIEW_LIMIT);
}}
className={`${
!isLoading && currentPage !== 1 ? styles.isActive : ""
}`}
>
</a>
{` ${total !== 0 ? currentPage : 0} of ${
total !== 0 ? totalPage : 0
} `}
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<a
onClick={() => {
movePage(currentPage * ACCOUNTS_VIEW_LIMIT);
}}
className={`${
!isLoading && currentPage < totalPage
? styles.isActive
: ""
}`}
>
</a>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<a
onClick={() => {
movePage((totalPage - 1) * ACCOUNTS_VIEW_LIMIT);
}}
className={` ${
!isLoading && currentPage < totalPage
? styles.isActive
: ""
}`}
>
»
</a>
</nav>
</div>
<img
style={{ display: isLoading ? "inline" : "none" }}
src={progress_activit}
className={styles.icLoading}
alt="Loading"
/>
</div>
</section>
</main>
<Footer />
</div>
)}
;
</>
);
};
export default PartnerLicense;