Merged PR 379: 画面実装(パートナー一覧画面本実装)
## 概要 [Task2539: 画面実装(パートナー一覧画面本実装)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2539) - 元PBI or タスクへのリンク(内容・目的などはそちらにあるはず) - 何をどう変更したか、追加したライブラリなど パートナー一覧画面でパートナーの一覧が表示されるように実装 - このPull Requestでの対象/対象外 ・Add Accountボタンは前PBIのため対象外 ・Dealer Managementボタンの挙動は対象外 ・Delete Accountボタンの挙動は対象外 - 影響範囲(他の機能にも影響があるか) 特になし ## レビューポイント - 特にレビューしてほしい箇所 ・Dealer Management、Delete Accountボタンの表示制御 ・ページネーション - 軽微なものや自明なものは記載不要 - 修正範囲が大きい場合などに記載 - 全体的にや仕様を満たしているか等は本当に必要な時のみ記載 ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 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/Task2539?csf=1&web=1&e=PNI5bw ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば
This commit is contained in:
parent
2dcb1c1f84
commit
606ff6de9b
1
dictation_client/src/features/partner/constants.ts
Normal file
1
dictation_client/src/features/partner/constants.ts
Normal file
@ -0,0 +1 @@
|
||||
export const LIMIT_PARTNER_VIEW_NUM = 15;
|
||||
@ -2,3 +2,4 @@ export * from "./state";
|
||||
export * from "./operations";
|
||||
export * from "./selectors";
|
||||
export * from "./partnerSlice";
|
||||
export * from "./constants";
|
||||
|
||||
@ -3,7 +3,11 @@ import type { RootState } from "app/store";
|
||||
import { ErrorObject, createErrorObject } from "common/errors";
|
||||
import { getTranslationID } from "translation";
|
||||
import { openSnackbar } from "features/ui/uiSlice";
|
||||
import { AccountsApi, CreatePartnerAccountRequest } from "../../api/api";
|
||||
import {
|
||||
AccountsApi,
|
||||
CreatePartnerAccountRequest,
|
||||
GetPartnersResponse,
|
||||
} from "../../api/api";
|
||||
import { Configuration } from "../../api/configuration";
|
||||
|
||||
export const createPartnerAccountAsync = createAsyncThunk<
|
||||
@ -62,3 +66,53 @@ export const createPartnerAccountAsync = createAsyncThunk<
|
||||
return thunkApi.rejectWithValue({ error });
|
||||
}
|
||||
});
|
||||
|
||||
// パートナー一覧取得APIからパートナーのアカウント情報をもらう
|
||||
export const getPartnerInfoAsync = createAsyncThunk<
|
||||
// 正常時の戻り値の型
|
||||
GetPartnersResponse,
|
||||
{
|
||||
// パラメータ
|
||||
limit: number;
|
||||
offset: number;
|
||||
},
|
||||
{
|
||||
// rejectした時の返却値の型
|
||||
rejectValue: {
|
||||
error: ErrorObject;
|
||||
};
|
||||
}
|
||||
>("partner/getPartnerInfoAsync", async (args, thunkApi) => {
|
||||
const { limit, offset } = args;
|
||||
const { getState } = thunkApi;
|
||||
const state = getState() as RootState;
|
||||
const { configuration, accessToken } = state.auth;
|
||||
const config = new Configuration(configuration);
|
||||
const accountsApi = new AccountsApi(config);
|
||||
|
||||
try {
|
||||
const res = await accountsApi.getPartners(limit, offset, {
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
const ret = {
|
||||
partners: res.data.partners,
|
||||
total: res.data.total,
|
||||
};
|
||||
return ret;
|
||||
} catch (e) {
|
||||
const error = createErrorObject(e);
|
||||
const errorMessage =
|
||||
error.code === "E000108"
|
||||
? getTranslationID("common.message.permissionDeniedError")
|
||||
: getTranslationID("common.message.internalServerError");
|
||||
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "error",
|
||||
message: errorMessage,
|
||||
})
|
||||
);
|
||||
|
||||
return thunkApi.rejectWithValue({ error });
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,8 +1,15 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { PartnerState } from "./state";
|
||||
import { createPartnerAccountAsync } from "./operations";
|
||||
import { createPartnerAccountAsync, getPartnerInfoAsync } from "./operations";
|
||||
import { LIMIT_PARTNER_VIEW_NUM } from "./constants";
|
||||
|
||||
const initialState: PartnerState = {
|
||||
domain: {
|
||||
getPartnersInfo: {
|
||||
total: 0,
|
||||
partners: [],
|
||||
},
|
||||
},
|
||||
apps: {
|
||||
addPartner: {
|
||||
companyName: "",
|
||||
@ -10,6 +17,8 @@ const initialState: PartnerState = {
|
||||
adminName: "",
|
||||
email: "",
|
||||
},
|
||||
limit: LIMIT_PARTNER_VIEW_NUM,
|
||||
offset: 0,
|
||||
isLoading: false,
|
||||
},
|
||||
};
|
||||
@ -37,6 +46,20 @@ export const partnerSlice = createSlice({
|
||||
cleanupAddPartner: (state) => {
|
||||
state.apps.addPartner = initialState.apps.addPartner;
|
||||
},
|
||||
cleanupApps: (state) => {
|
||||
state.domain = initialState.domain;
|
||||
},
|
||||
savePageInfo: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
limit: number;
|
||||
offset: number;
|
||||
}>
|
||||
) => {
|
||||
const { limit, offset } = action.payload;
|
||||
state.apps.limit = limit;
|
||||
state.apps.offset = offset;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(createPartnerAccountAsync.pending, (state) => {
|
||||
@ -48,6 +71,17 @@ export const partnerSlice = createSlice({
|
||||
builder.addCase(createPartnerAccountAsync.rejected, (state) => {
|
||||
state.apps.isLoading = false;
|
||||
});
|
||||
builder.addCase(getPartnerInfoAsync.pending, (state) => {
|
||||
state.apps.isLoading = true;
|
||||
});
|
||||
builder.addCase(getPartnerInfoAsync.fulfilled, (state, action) => {
|
||||
state.domain.getPartnersInfo.total = action.payload.total;
|
||||
state.domain.getPartnersInfo.partners = action.payload.partners;
|
||||
state.apps.isLoading = false;
|
||||
});
|
||||
builder.addCase(getPartnerInfoAsync.rejected, (state) => {
|
||||
state.apps.isLoading = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
export const {
|
||||
@ -56,5 +90,6 @@ export const {
|
||||
changeCompany,
|
||||
changeCountry,
|
||||
cleanupAddPartner,
|
||||
savePageInfo,
|
||||
} = partnerSlice.actions;
|
||||
export default partnerSlice.reducer;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { RootState } from "app/store";
|
||||
import { ceil, floor } from "lodash";
|
||||
|
||||
export const selectInputValidationErrors = (state: RootState) => {
|
||||
// 必須項目のチェック
|
||||
@ -33,3 +34,22 @@ export const selectEmail = (state: RootState) =>
|
||||
state.partner.apps.addPartner.email;
|
||||
export const selectIsLoading = (state: RootState) =>
|
||||
state.partner.apps.isLoading;
|
||||
|
||||
export const selectPartnersInfo = (state: RootState) =>
|
||||
state.partner.domain.getPartnersInfo;
|
||||
export const selectTotal = (state: RootState) =>
|
||||
state.partner.domain.getPartnersInfo.total;
|
||||
export const seletctLimit = (state: RootState) => state.partner.apps.limit;
|
||||
export const selectOffset = (state: RootState) => state.partner.apps.offset;
|
||||
export const selectTotalPage = (state: RootState) => {
|
||||
const { limit } = state.partner.apps;
|
||||
const { total } = state.partner.domain.getPartnersInfo;
|
||||
const page = ceil(total / limit);
|
||||
return page;
|
||||
};
|
||||
|
||||
export const selectCurrentPage = (state: RootState) => {
|
||||
const { limit, offset } = state.partner.apps;
|
||||
const page = floor(offset / limit) + 1;
|
||||
return page;
|
||||
};
|
||||
|
||||
@ -1,10 +1,20 @@
|
||||
import { CreatePartnerAccountRequest } from "../../api/api";
|
||||
import {
|
||||
CreatePartnerAccountRequest,
|
||||
GetPartnersResponse,
|
||||
} from "../../api/api";
|
||||
|
||||
export interface PartnerState {
|
||||
domain: Domain;
|
||||
apps: Apps;
|
||||
}
|
||||
|
||||
export interface Domain {
|
||||
getPartnersInfo: GetPartnersResponse;
|
||||
}
|
||||
|
||||
export interface Apps {
|
||||
limit: number;
|
||||
offset: number;
|
||||
addPartner: CreatePartnerAccountRequest;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
@ -1,44 +1,89 @@
|
||||
import { useMsal } from "@azure/msal-react";
|
||||
/* eslint-disable jsx-a11y/control-has-associated-label */
|
||||
import { AppDispatch } from "app/store";
|
||||
import { UpdateTokenTimer } from "components/auth/updateTokenTimer";
|
||||
import Footer from "components/footer";
|
||||
import Header from "components/header";
|
||||
import { clearToken } from "features/auth";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import styles from "styles/app.module.scss";
|
||||
import { loadAccessToken, isApproveTier } from "features/auth/utils";
|
||||
import postAdd from "../../assets/images/post_add.svg";
|
||||
import { decodeToken } from "../../common/decodeToken";
|
||||
import { isApproveTier } from "features/auth/utils";
|
||||
import {
|
||||
LIMIT_PARTNER_VIEW_NUM,
|
||||
selectCurrentPage,
|
||||
selectIsLoading,
|
||||
selectOffset,
|
||||
selectTotal,
|
||||
selectTotalPage,
|
||||
getPartnerInfoAsync,
|
||||
selectPartnersInfo,
|
||||
} from "features/partner/index";
|
||||
import { savePageInfo } from "features/partner/partnerSlice";
|
||||
import { getTranslationID } from "translation";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import personAdd from "../../assets/images/person_add.svg";
|
||||
import { TIERS } from "../../components/auth/constants";
|
||||
import { AddPartnerAccountPopup } from "./addPartnerAccountPopup";
|
||||
import checkFill from "../../assets/images/check_fill.svg";
|
||||
|
||||
const PartnerPage: React.FC = (): JSX.Element => {
|
||||
const { instance } = useMsal();
|
||||
const dispatch: AppDispatch = useDispatch();
|
||||
const [isPopupOpen, setIsPopupOpen] = useState(false);
|
||||
const [t] = useTranslation();
|
||||
const total = useSelector(selectTotal);
|
||||
const totalPage = useSelector(selectTotalPage);
|
||||
const offset = useSelector(selectOffset);
|
||||
const currentPage = useSelector(selectCurrentPage);
|
||||
const isLoading = useSelector(selectIsLoading);
|
||||
|
||||
/* XXX 本実装の際に消す想定です。
|
||||
POデモ時に階層情報を表示するための実装です。 */
|
||||
const getUserTier = () => {
|
||||
const jwt = loadAccessToken(); // トークンを取得
|
||||
const token = jwt && decodeToken(jwt); // トークンをデコード
|
||||
// apiからの値取得関係
|
||||
const partnerInfo = useSelector(selectPartnersInfo);
|
||||
|
||||
if (token && token.tier) {
|
||||
return token.tier.toString(); // ユーザーの階層情報を取得
|
||||
}
|
||||
|
||||
return "error!"; // 階層情報が見つからない場合はerror!を返す
|
||||
// 階層表示用
|
||||
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")),
|
||||
};
|
||||
|
||||
/* XXX 本実装の際に消す想定です。
|
||||
ログインしているアカウントの階層を確認するために実装 */
|
||||
const userTier = getUserTier();
|
||||
// 第1~3階層にボタンを表示する
|
||||
const isVisible = isApproveTier([TIERS.TIER1, TIERS.TIER2, TIERS.TIER3]);
|
||||
const isVisibleButton = isApproveTier([
|
||||
TIERS.TIER1,
|
||||
TIERS.TIER2,
|
||||
TIERS.TIER3,
|
||||
]);
|
||||
|
||||
// 第4階層でdealerManagementを表示
|
||||
const isVisibleDealerManagement = isApproveTier([TIERS.TIER4]);
|
||||
|
||||
const onOpen = useCallback(() => {
|
||||
setIsPopupOpen(true);
|
||||
}, [setIsPopupOpen]);
|
||||
|
||||
// パートナー取得APIを呼び出す
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
getPartnerInfoAsync({
|
||||
limit: LIMIT_PARTNER_VIEW_NUM,
|
||||
offset,
|
||||
})
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dispatch, currentPage]);
|
||||
|
||||
// ページネーションのボタンクリック時のアクション
|
||||
const movePage = (targetOffset: number) => {
|
||||
dispatch(
|
||||
savePageInfo({ limit: LIMIT_PARTNER_VIEW_NUM, offset: targetOffset })
|
||||
);
|
||||
};
|
||||
|
||||
// HTML
|
||||
return (
|
||||
<>
|
||||
@ -52,52 +97,167 @@ const PartnerPage: React.FC = (): JSX.Element => {
|
||||
<Header userName="XXXXXX" />
|
||||
<UpdateTokenTimer />
|
||||
<main className={styles.main}>
|
||||
<ul className={styles.menuAction}>
|
||||
<li>
|
||||
{isVisible && (
|
||||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
|
||||
<a
|
||||
className={`${styles.menuLink} ${styles.isActive}`}
|
||||
onClick={onOpen}
|
||||
>
|
||||
<img src={postAdd} alt="" className={styles.menuIcon} />
|
||||
Add Account
|
||||
</a>
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
<form className={styles.form}>
|
||||
<dl className={`${styles.formList} ${styles.hasbg}`}>
|
||||
<dt className={styles.formTitle} />
|
||||
<dt />
|
||||
<dd className="">
|
||||
<input
|
||||
type="text"
|
||||
size={40}
|
||||
name=""
|
||||
value={`Tier:${userTier}`}
|
||||
maxLength={20}
|
||||
className={styles.formInput}
|
||||
/>
|
||||
</dd>
|
||||
</dl>
|
||||
</form>
|
||||
<div className={styles.pageHeader}>
|
||||
<h1 className={styles.pageTitle}>
|
||||
{t(getTranslationID("partnerPage.label.title"))}
|
||||
</h1>
|
||||
</div>
|
||||
<section className={styles.partners}>
|
||||
<div>
|
||||
<ul className={styles.menuAction}>
|
||||
<li>
|
||||
{isVisibleButton && (
|
||||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
|
||||
<a
|
||||
className={`${styles.menuLink} ${styles.isActive}`}
|
||||
onClick={onOpen}
|
||||
>
|
||||
<img src={personAdd} alt="" className={styles.menuIcon} />
|
||||
{t(getTranslationID("partnerPage.label.addAccount"))}
|
||||
</a>
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
<table
|
||||
className={`${styles.table} ${styles.partner} ${
|
||||
styles.marginBtm3
|
||||
} ${isVisibleDealerManagement ? styles.role4 : ""}`}
|
||||
>
|
||||
<tr className={styles.tableHeader}>
|
||||
<th className={styles.clm0}>{/** th is empty */}</th>
|
||||
<th>
|
||||
<a>{t(getTranslationID("partnerPage.label.name"))}</a>
|
||||
</th>
|
||||
<th>
|
||||
<a>{t(getTranslationID("partnerPage.label.category"))}</a>
|
||||
</th>
|
||||
<th>
|
||||
<a>{t(getTranslationID("partnerPage.label.accountId"))}</a>
|
||||
</th>
|
||||
<th>
|
||||
<a>{t(getTranslationID("partnerPage.label.country"))}</a>
|
||||
</th>
|
||||
<th>
|
||||
<a>
|
||||
{t(getTranslationID("partnerPage.label.primaryAdmin"))}
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a>{t(getTranslationID("partnerPage.label.email"))}</a>
|
||||
</th>
|
||||
<th>
|
||||
<a>
|
||||
{t(
|
||||
getTranslationID("partnerPage.label.dealerManagement")
|
||||
)}
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
{!isLoading &&
|
||||
partnerInfo.partners.length !== 0 &&
|
||||
partnerInfo.partners.map((x) => (
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<tr>
|
||||
<td className={styles.clm0}>
|
||||
<ul className={styles.menuInTable}>
|
||||
<li>
|
||||
{isVisibleButton && (
|
||||
<a>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"partnerPage.label.deleteAccount"
|
||||
)
|
||||
)}
|
||||
</a>
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>{x.name}</td>
|
||||
<td>{tierNames[x.tier]}</td>
|
||||
<td>{x.accountId}</td>
|
||||
<td>{x.country}</td>
|
||||
<td>{x.primaryAdmin ?? "-"}</td>
|
||||
<td>{x.email ?? "-"}</td>
|
||||
<td>
|
||||
<img
|
||||
src={checkFill}
|
||||
alt=""
|
||||
className={styles.icCheckCircle}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</table>
|
||||
{/** pagenation */}
|
||||
<div className={styles.pagenation}>
|
||||
<nav className={styles.pagenationNav}>
|
||||
<span className={styles.pagenationTotal}>
|
||||
{`${total} ${t(
|
||||
getTranslationID("partnerPage.label.partners")
|
||||
)}`}
|
||||
</span>
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
|
||||
<a
|
||||
className={`${
|
||||
!isLoading && currentPage !== 1 ? styles.isActive : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
movePage(0);
|
||||
}}
|
||||
>
|
||||
«
|
||||
</a>
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||||
<a
|
||||
className={`${
|
||||
!isLoading && currentPage !== 1 ? styles.isActive : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
movePage((currentPage - 2) * LIMIT_PARTNER_VIEW_NUM);
|
||||
}}
|
||||
>
|
||||
‹
|
||||
</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
|
||||
className={`${
|
||||
!isLoading && currentPage < totalPage
|
||||
? styles.isActive
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
movePage(currentPage * LIMIT_PARTNER_VIEW_NUM);
|
||||
}}
|
||||
>
|
||||
›
|
||||
</a>
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||||
<a
|
||||
className={`${
|
||||
!isLoading && currentPage < totalPage
|
||||
? styles.isActive
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
movePage((totalPage - 1) * LIMIT_PARTNER_VIEW_NUM);
|
||||
}}
|
||||
>
|
||||
»
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.buttonText}
|
||||
onClick={() => {
|
||||
instance.logout({ postLogoutRedirectUri: "/" });
|
||||
dispatch(clearToken());
|
||||
}}
|
||||
>
|
||||
sign out
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PartnerPage;
|
||||
|
||||
@ -2165,8 +2165,7 @@ tr.isSelected .menuInTable li a {
|
||||
}
|
||||
.formChange ul.chooseMember li input + label:hover,
|
||||
.formChange ul.holdMember li input + label:hover {
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left
|
||||
center;
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left center;
|
||||
background-size: 1.3rem;
|
||||
}
|
||||
.formChange ul.chooseMember li input:checked + label,
|
||||
@ -2177,8 +2176,8 @@ tr.isSelected .menuInTable li a {
|
||||
}
|
||||
.formChange ul.chooseMember li input:checked + label:hover,
|
||||
.formChange ul.holdMember li input:checked + label:hover {
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat
|
||||
right center;
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat right
|
||||
center;
|
||||
background-size: 1.3rem;
|
||||
}
|
||||
.formChange > p {
|
||||
@ -2337,8 +2336,7 @@ tr.isSelected .menuInTable li a {
|
||||
}
|
||||
.formChange ul.chooseMember li input + label:hover,
|
||||
.formChange ul.holdMember li input + label:hover {
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left
|
||||
center;
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left center;
|
||||
background-size: 1.3rem;
|
||||
}
|
||||
.formChange ul.chooseMember li input:checked + label,
|
||||
@ -2349,8 +2347,8 @@ tr.isSelected .menuInTable li a {
|
||||
}
|
||||
.formChange ul.chooseMember li input:checked + label:hover,
|
||||
.formChange ul.holdMember li input:checked + label:hover {
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat
|
||||
right center;
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat right
|
||||
center;
|
||||
background-size: 1.3rem;
|
||||
}
|
||||
.formChange > p {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user