계정 관리 페이지 및 컴포넌트 다국어화 완료
- 계정 관리 페이지 전체 다국어화 (8개 페이지) * 사용자 관리: 계정 추가, 메뉴 권한, 계정 정보, 로그인 인증정보 * 비밀번호 관리: 로그인/취소 비밀번호 변경 - 계정 엔티티 컴포넌트 다국어화 * account-tab: 사용자 관리/비밀번호 관리 탭 * account-user-tab: 로그인 인증정보/계정권한 서브탭 * password-manage-wrap: 비밀번호 변경 버튼 * user-manage-wrap: 등록 현황, 사용자 추가 버튼 * user-login-auth-info-wrap: 이메일/휴대폰 관리 인터페이스 - 계정 추가 페이지 상세 다국어화 * 폼 라벨: 사용자ID, 비밀번호, 로그인 범위 * 본인인증 정보 입력 섹션 * 유효성 검사 메시지 * 성공/실패 알림 메시지 - 메뉴 권한 페이지 다국어화 * 권한 설정 안내 메시지 * 저장/실행/다운로드 권한 라벨 * 탭 변경 시 초기화 안내 - 번역 키 추가: account 네임스페이스 50개 키 - 모든 폼, 버튼, 알림 메시지 일관된 다국어 지원 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import {
|
import {
|
||||||
@@ -8,6 +9,7 @@ import {
|
|||||||
export const AccountTab = ({
|
export const AccountTab = ({
|
||||||
activeTab
|
activeTab
|
||||||
}: AccountTabProps) => {
|
}: AccountTabProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
|
|
||||||
const onClickToNavigation = (tab: AccountTabKeys) => {
|
const onClickToNavigation = (tab: AccountTabKeys) => {
|
||||||
@@ -26,11 +28,11 @@ export const AccountTab = ({
|
|||||||
<button
|
<button
|
||||||
className={`subtab-btn ${(activeTab === AccountTabKeys.UserManage)? 'active': ''}` }
|
className={`subtab-btn ${(activeTab === AccountTabKeys.UserManage)? 'active': ''}` }
|
||||||
onClick={ () => onClickToNavigation(AccountTabKeys.UserManage) }
|
onClick={ () => onClickToNavigation(AccountTabKeys.UserManage) }
|
||||||
>사용자 관리</button>
|
>{t('account.userManagement')}</button>
|
||||||
<button
|
<button
|
||||||
className={`subtab-btn ${(activeTab === AccountTabKeys.PasswordManage)? 'active': ''}` }
|
className={`subtab-btn ${(activeTab === AccountTabKeys.PasswordManage)? 'active': ''}` }
|
||||||
onClick={ () => onClickToNavigation(AccountTabKeys.PasswordManage) }
|
onClick={ () => onClickToNavigation(AccountTabKeys.PasswordManage) }
|
||||||
>비밀번호 관리</button>
|
>{t('account.passwordManagement')}</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import {
|
import {
|
||||||
@@ -12,6 +13,7 @@ export const AccountUserTab = ({
|
|||||||
idCL,
|
idCL,
|
||||||
status,
|
status,
|
||||||
}: AccountUserTabProps) => {
|
}: AccountUserTabProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
|
|
||||||
const onClickToNavigation = (tab: AccountUserTabKeys) => {
|
const onClickToNavigation = (tab: AccountUserTabKeys) => {
|
||||||
@@ -44,11 +46,11 @@ export const AccountUserTab = ({
|
|||||||
<button
|
<button
|
||||||
className={`subtab-btn ${(activeTab === AccountUserTabKeys.LoginAuthInfo)? 'active': ''}` }
|
className={`subtab-btn ${(activeTab === AccountUserTabKeys.LoginAuthInfo)? 'active': ''}` }
|
||||||
onClick={ () => onClickToNavigation(AccountUserTabKeys.LoginAuthInfo) }
|
onClick={ () => onClickToNavigation(AccountUserTabKeys.LoginAuthInfo) }
|
||||||
>로그인 인증정보</button>
|
>{t('account.loginAuthInfo')}</button>
|
||||||
<button
|
<button
|
||||||
className={`subtab-btn ${(activeTab === AccountUserTabKeys.AccountAuth)? 'active': ''}` }
|
className={`subtab-btn ${(activeTab === AccountUserTabKeys.AccountAuth)? 'active': ''}` }
|
||||||
onClick={ () => onClickToNavigation( AccountUserTabKeys.AccountAuth) }
|
onClick={ () => onClickToNavigation( AccountUserTabKeys.AccountAuth) }
|
||||||
>계정권한</button>
|
>{t('account.accountPermission')}</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
|
|
||||||
export const PasswordManageWrap = () => {
|
export const PasswordManageWrap = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -13,12 +15,12 @@ export const PasswordManageWrap = () => {
|
|||||||
className="btn-44 btn-white pwd-btn"
|
className="btn-44 btn-white pwd-btn"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={ () => navigate(PATHS.account.password.modifyLoginPassword) }
|
onClick={ () => navigate(PATHS.account.password.modifyLoginPassword) }
|
||||||
>로그인 비밀번호 변경</button>
|
>{t('account.changeLoginPassword')}</button>
|
||||||
<button
|
<button
|
||||||
className="btn-44 btn-white pwd-btn"
|
className="btn-44 btn-white pwd-btn"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={ () => navigate(PATHS.account.password.modifyCancelPassword) }
|
onClick={ () => navigate(PATHS.account.password.modifyCancelPassword) }
|
||||||
>거래취소 비밀번호 변경</button>
|
>{t('account.changeCancelPassword')}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { UserFindAuthMethodParams, UserAuthMethodData, AuthMethodModifyItem } from '@/entities/user/model/types';
|
import { UserFindAuthMethodParams, UserAuthMethodData, AuthMethodModifyItem } from '@/entities/user/model/types';
|
||||||
import { useUserFindAuthMethodMutation } from '@/entities/user/api/use-user-find-authmethod-mutation';
|
import { useUserFindAuthMethodMutation } from '@/entities/user/api/use-user-find-authmethod-mutation';
|
||||||
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
||||||
@@ -13,6 +14,7 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
idCL,
|
idCL,
|
||||||
status,
|
status,
|
||||||
}: UserFindAuthMethodParams) => {
|
}: UserFindAuthMethodParams) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
const [pageParam] = useState(DEFAULT_PAGE_PARAM);
|
const [pageParam] = useState(DEFAULT_PAGE_PARAM);
|
||||||
const [authMethodData, setAuthMethodData] = useState<UserAuthMethodData>();
|
const [authMethodData, setAuthMethodData] = useState<UserAuthMethodData>();
|
||||||
@@ -26,7 +28,7 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
const { mutateAsync: userFindAuthMethod } = useUserFindAuthMethodMutation();
|
const { mutateAsync: userFindAuthMethod } = useUserFindAuthMethodMutation();
|
||||||
const { mutateAsync: userModifyAuthMethod } = useUserModifyAuthMethodMutation({
|
const { mutateAsync: userModifyAuthMethod } = useUserModifyAuthMethodMutation({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
snackBar('사용자 정보가 성공적으로 저장되었습니다.');
|
snackBar(t('account.userInfoSavedSuccessfully'));
|
||||||
navigate(PATHS.account.user.manage, {
|
navigate(PATHS.account.user.manage, {
|
||||||
state: {
|
state: {
|
||||||
mid: mid,
|
mid: mid,
|
||||||
@@ -34,7 +36,7 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
snackBar(error?.response?.data?.message || '사용자 정보 저장에 실패했습니다.');
|
snackBar(error?.response?.data?.message || t('account.userInfoSaveFailed'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -395,11 +397,11 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
<div className="settings-login-auth pb-86">
|
<div className="settings-login-auth pb-86">
|
||||||
<div className="group">
|
<div className="group">
|
||||||
<div className="group-header">
|
<div className="group-header">
|
||||||
<div className="title">이메일 주소</div>
|
<div className="title">{t('account.emailAddress')}</div>
|
||||||
<button
|
<button
|
||||||
className="ic20 plus"
|
className="ic20 plus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="추가"
|
aria-label={t('common.add')}
|
||||||
onClick={handleAddEmail}
|
onClick={handleAddEmail}
|
||||||
disabled={!isEmailAddButtonEnabled()}
|
disabled={!isEmailAddButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
@@ -415,7 +417,7 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
<button
|
<button
|
||||||
className="icon-btn minus"
|
className="icon-btn minus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="삭제"
|
aria-label={t('common.delete')}
|
||||||
onClick={() => handleRemoveExistingEmail(index)}
|
onClick={() => handleRemoveExistingEmail(index)}
|
||||||
disabled={!isDeleteButtonEnabled()}
|
disabled={!isDeleteButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
@@ -433,7 +435,7 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
<button
|
<button
|
||||||
className="icon-btn minus"
|
className="icon-btn minus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="삭제"
|
aria-label={t('common.delete')}
|
||||||
onClick={() => handleRemoveNewEmail(index)}
|
onClick={() => handleRemoveNewEmail(index)}
|
||||||
disabled={!isDeleteButtonEnabled()}
|
disabled={!isDeleteButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
@@ -443,11 +445,11 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
|
|
||||||
<div className="group">
|
<div className="group">
|
||||||
<div className="group-header">
|
<div className="group-header">
|
||||||
<div className="title">휴대폰 번호</div>
|
<div className="title">{t('account.phoneNumber')}</div>
|
||||||
<button
|
<button
|
||||||
className="ic20 plus"
|
className="ic20 plus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="추가"
|
aria-label={t('common.add')}
|
||||||
onClick={handleAddPhone}
|
onClick={handleAddPhone}
|
||||||
disabled={!isPhoneAddButtonEnabled()}
|
disabled={!isPhoneAddButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
@@ -457,13 +459,13 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
value={phone.content}
|
value={phone.content}
|
||||||
placeholder="휴대폰 번호 입력"
|
placeholder={t('account.enterPhoneNumber')}
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
className="icon-btn minus"
|
className="icon-btn minus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="삭제"
|
aria-label={t('common.delete')}
|
||||||
onClick={() => handleRemoveExistingPhone(index)}
|
onClick={() => handleRemoveExistingPhone(index)}
|
||||||
disabled={!isDeleteButtonEnabled()}
|
disabled={!isDeleteButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
@@ -474,20 +476,20 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
value={phone}
|
value={phone}
|
||||||
placeholder="휴대폰 번호 입력"
|
placeholder={t('account.enterPhoneNumber')}
|
||||||
onChange={(e) => handleNewPhoneChange(index, e.target.value)}
|
onChange={(e) => handleNewPhoneChange(index, e.target.value)}
|
||||||
readOnly={readOnlyPhones.has(index) || index !== editablePhoneIndex}
|
readOnly={readOnlyPhones.has(index) || index !== editablePhoneIndex}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
className="icon-btn minus"
|
className="icon-btn minus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="삭제"
|
aria-label={t('common.delete')}
|
||||||
onClick={() => handleRemoveNewPhone(index)}
|
onClick={() => handleRemoveNewPhone(index)}
|
||||||
disabled={!isDeleteButtonEnabled()}
|
disabled={!isDeleteButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<div className="notice-bar">※ 탭을 변경하면 미저장 내용은 초기화됩니다.</div>
|
<div className="notice-bar">{t('account.tabChangeResetNotice')}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="apply-row">
|
<div className="apply-row">
|
||||||
@@ -496,7 +498,7 @@ export const UserLoginAuthInfoWrap = ({
|
|||||||
disabled={!isSaveButtonEnabled()}
|
disabled={!isSaveButtonEnabled()}
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
>
|
>
|
||||||
저장
|
{t('common.save')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ChangeEvent, useEffect, useState } from 'react';
|
import { ChangeEvent, useEffect, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
||||||
@@ -8,6 +9,7 @@ import { UserListItem } from '@/entities/user/model/types';
|
|||||||
import { useStore } from '@/shared/model/store';
|
import { useStore } from '@/shared/model/store';
|
||||||
|
|
||||||
export const UserManageWrap = () => {
|
export const UserManageWrap = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
const midOptions = useStore.getState().UserStore.selectOptionsMids;
|
const midOptions = useStore.getState().UserStore.selectOptionsMids;
|
||||||
const userMid = useStore.getState().UserStore.mid;
|
const userMid = useStore.getState().UserStore.mid;
|
||||||
@@ -60,7 +62,7 @@ export const UserManageWrap = () => {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="ing-title">등록 현황</div>
|
<div className="ing-title">{t('account.registrationStatus')}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ flex: 1, overflow: 'hidden', minHeight: 0 }}>
|
<div style={{ flex: 1, overflow: 'hidden', minHeight: 0 }}>
|
||||||
@@ -76,7 +78,7 @@ export const UserManageWrap = () => {
|
|||||||
<button
|
<button
|
||||||
className="btn-50 btn-blue flex-1"
|
className="btn-50 btn-blue flex-1"
|
||||||
onClick={ () => onClickToNavigation() }
|
onClick={ () => onClickToNavigation() }
|
||||||
>사용자 추가</button>
|
>{t('account.addUser')}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -189,6 +189,56 @@
|
|||||||
"logout": "Logout"
|
"logout": "Logout"
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
|
"title": "Account Management",
|
||||||
|
"userManagement": "User Management",
|
||||||
|
"passwordManagement": "Password Management",
|
||||||
|
"userSettings": "User Settings",
|
||||||
|
"addUser": "Add User",
|
||||||
|
"addAccount": "Add Account",
|
||||||
|
"loginAuthInfo": "Login Authentication Info",
|
||||||
|
"accountPermission": "Account Permission",
|
||||||
|
"registrationStatus": "Registration Status",
|
||||||
|
"userId": "User ID",
|
||||||
|
"password": "Password",
|
||||||
|
"loginRange": "Login Range",
|
||||||
|
"merchant": "Merchant",
|
||||||
|
"currentPassword": "Current Password",
|
||||||
|
"newPassword": "New Password",
|
||||||
|
"reEnterNewPassword": "Re-enter New Password",
|
||||||
|
"changeLoginPassword": "Change Login Password",
|
||||||
|
"changeCancelPassword": "Change Cancel Password",
|
||||||
|
"identityVerificationInfo": "Identity Verification Information",
|
||||||
|
"identityVerificationNotice": "The information you provide will be used for login and sending merchant-related materials.",
|
||||||
|
"emailAddress": "Email Address",
|
||||||
|
"phoneNumber": "Phone Number",
|
||||||
|
"addEmail": "Add Email",
|
||||||
|
"addPhone": "Add Phone",
|
||||||
|
"pleaseEnterId": "Please enter ID",
|
||||||
|
"pleaseEnterPassword": "Please enter password",
|
||||||
|
"pleaseEnter8OrMoreCharacters": "Please enter 8 or more characters",
|
||||||
|
"enterPassword": "Enter password",
|
||||||
|
"reEnterPassword": "Re-enter password",
|
||||||
|
"enterPhoneNumber": "Enter phone number",
|
||||||
|
"checking": "Checking...",
|
||||||
|
"availableId": "This ID is available.",
|
||||||
|
"duplicateIdExists": "This ID already exists.",
|
||||||
|
"inputMismatch": "Input mismatch",
|
||||||
|
"processing": "Processing...",
|
||||||
|
"userAddedSuccessfully": "User added successfully.",
|
||||||
|
"userAddFailed": "Failed to add user.",
|
||||||
|
"userInfoSavedSuccessfully": "User information saved successfully.",
|
||||||
|
"userInfoSaveFailed": "Failed to save user information.",
|
||||||
|
"passwordChangedSuccessfully": "Password changed successfully.",
|
||||||
|
"passwordChangeFailed": "Failed to change password.",
|
||||||
|
"permissionSavedSuccessfully": "Permission saved successfully.",
|
||||||
|
"permissionSaveFailed": "Failed to save permission.",
|
||||||
|
"permissionSaved": "Permission saved.",
|
||||||
|
"setMenuPermissions": "Please set menu permissions.",
|
||||||
|
"permissionRestrictionsNotice": "Function usage will be restricted according to selected permissions.",
|
||||||
|
"save": "Save",
|
||||||
|
"execute": "Execute",
|
||||||
|
"download": "Download",
|
||||||
|
"tabChangeResetNotice": "※ Unsaved content will be reset when switching tabs.",
|
||||||
"accountStatus": "Account Status",
|
"accountStatus": "Account Status",
|
||||||
"active": "Active",
|
"active": "Active",
|
||||||
"inactive": "Inactive",
|
"inactive": "Inactive",
|
||||||
|
|||||||
@@ -194,6 +194,56 @@
|
|||||||
"logout": "로그아웃"
|
"logout": "로그아웃"
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
|
"title": "계정 관리",
|
||||||
|
"userManagement": "사용자 관리",
|
||||||
|
"passwordManagement": "비밀번호 관리",
|
||||||
|
"userSettings": "사용자 설정",
|
||||||
|
"addUser": "사용자 추가",
|
||||||
|
"addAccount": "계정 추가",
|
||||||
|
"loginAuthInfo": "로그인 인증정보",
|
||||||
|
"accountPermission": "계정권한",
|
||||||
|
"registrationStatus": "등록 현황",
|
||||||
|
"userId": "사용자ID",
|
||||||
|
"password": "비밀번호",
|
||||||
|
"loginRange": "로그인 범위",
|
||||||
|
"merchant": "가맹점",
|
||||||
|
"currentPassword": "기존 비밀번호",
|
||||||
|
"newPassword": "변경 비밀번호",
|
||||||
|
"reEnterNewPassword": "변경 비밀번호 재입력",
|
||||||
|
"changeLoginPassword": "로그인 비밀번호 변경",
|
||||||
|
"changeCancelPassword": "거래취소 비밀번호 변경",
|
||||||
|
"identityVerificationInfo": "본인인증용 정보 입력",
|
||||||
|
"identityVerificationNotice": "입력하신 정보는 이후 로그인 및 가맹점 관련 자료 발송에 이용됩니다.",
|
||||||
|
"emailAddress": "이메일 주소",
|
||||||
|
"phoneNumber": "휴대폰 번호",
|
||||||
|
"addEmail": "이메일 추가",
|
||||||
|
"addPhone": "휴대폰 추가",
|
||||||
|
"pleaseEnterId": "ID를 입력해 주세요",
|
||||||
|
"pleaseEnterPassword": "비밀번호를 입력해 주세요",
|
||||||
|
"pleaseEnter8OrMoreCharacters": "8자리 이상 입력해 주세요",
|
||||||
|
"enterPassword": "비밀번호를 입력하세요",
|
||||||
|
"reEnterPassword": "비밀번호를 다시 입력하세요",
|
||||||
|
"enterPhoneNumber": "휴대폰 번호 입력",
|
||||||
|
"checking": "확인 중...",
|
||||||
|
"availableId": "사용 가능한 ID입니다.",
|
||||||
|
"duplicateIdExists": "동일한 ID가 이미 존재합니다.",
|
||||||
|
"inputMismatch": "입력 정보 불일치",
|
||||||
|
"processing": "처리중...",
|
||||||
|
"userAddedSuccessfully": "사용자가 성공적으로 추가되었습니다.",
|
||||||
|
"userAddFailed": "사용자 추가에 실패했습니다.",
|
||||||
|
"userInfoSavedSuccessfully": "사용자 정보가 성공적으로 저장되었습니다.",
|
||||||
|
"userInfoSaveFailed": "사용자 정보 저장에 실패했습니다.",
|
||||||
|
"passwordChangedSuccessfully": "비밀번호가 성공적으로 변경되었습니다.",
|
||||||
|
"passwordChangeFailed": "비밀번호 변경에 실패했습니다.",
|
||||||
|
"permissionSavedSuccessfully": "권한이 성공적으로 저장되었습니다.",
|
||||||
|
"permissionSaveFailed": "권한 저장에 실패했습니다.",
|
||||||
|
"permissionSaved": "권한이 저장되었습니다.",
|
||||||
|
"setMenuPermissions": "메뉴별 사용 권한을 설정해 주세요.",
|
||||||
|
"permissionRestrictionsNotice": "선택한 권한에 따라 기능 이용이 제한됩니다.",
|
||||||
|
"save": "저장",
|
||||||
|
"execute": "실행",
|
||||||
|
"download": "다운로드",
|
||||||
|
"tabChangeResetNotice": "※ 탭을 변경하면 미저장 내용은 초기화됩니다.",
|
||||||
"accountStatus": "계정 상태",
|
"accountStatus": "계정 상태",
|
||||||
"active": "사용",
|
"active": "사용",
|
||||||
"inactive": "미사용",
|
"inactive": "미사용",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { AccountTab } from '@/entities/account/ui/account-tab';
|
import { AccountTab } from '@/entities/account/ui/account-tab';
|
||||||
@@ -13,10 +14,11 @@ import {
|
|||||||
} from '@/widgets/sub-layout/use-sub-layout';
|
} from '@/widgets/sub-layout/use-sub-layout';
|
||||||
|
|
||||||
export const PasswordManagePage = () => {
|
export const PasswordManagePage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState<AccountTabKeys>(AccountTabKeys.PasswordManage);
|
const [activeTab, setActiveTab] = useState<AccountTabKeys>(AccountTabKeys.PasswordManage);
|
||||||
useSetHeaderTitle(t('account.manage'));
|
useSetHeaderTitle(t('account.title'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(false);
|
useSetFooterMode(false);
|
||||||
useSetOnBack(() => {
|
useSetOnBack(() => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { HeaderType } from '@/entities/common/model/types';
|
import { HeaderType } from '@/entities/common/model/types';
|
||||||
@@ -13,6 +14,7 @@ import { useStore } from '@/shared/model/store';
|
|||||||
import { snackBar } from '@/shared/lib/toast';
|
import { snackBar } from '@/shared/lib/toast';
|
||||||
|
|
||||||
export const PasswordModifyCancelPasswordPage = () => {
|
export const PasswordModifyCancelPasswordPage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
const midOptions = useStore.getState().UserStore.selectOptionsMids;
|
const midOptions = useStore.getState().UserStore.selectOptionsMids;
|
||||||
const userMid = useStore.getState().UserStore.mid;
|
const userMid = useStore.getState().UserStore.mid;
|
||||||
@@ -23,7 +25,7 @@ export const PasswordModifyCancelPasswordPage = () => {
|
|||||||
|
|
||||||
const changeCancelPasswordMutation = useUserChangeCancelPasswordMutation({
|
const changeCancelPasswordMutation = useUserChangeCancelPasswordMutation({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
snackBar('비밀번호가 성공적으로 변경되었습니다.');
|
snackBar(t('account.passwordChangedSuccessfully'));
|
||||||
// Clear form
|
// Clear form
|
||||||
setPassword('');
|
setPassword('');
|
||||||
setConfirmPassword('');
|
setConfirmPassword('');
|
||||||
@@ -31,11 +33,11 @@ export const PasswordModifyCancelPasswordPage = () => {
|
|||||||
navigate(PATHS.account.password.manage);
|
navigate(PATHS.account.password.manage);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
|
snackBar(error?.response?.data?.message || t('account.passwordChangeFailed'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
useSetHeaderTitle('거래취소 비밀번호 변경');
|
useSetHeaderTitle(t('account.changeCancelPassword'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(false);
|
useSetFooterMode(false);
|
||||||
useSetOnBack(() => {
|
useSetOnBack(() => {
|
||||||
@@ -69,7 +71,7 @@ export const PasswordModifyCancelPasswordPage = () => {
|
|||||||
<div className="ing-list add">
|
<div className="ing-list add">
|
||||||
<div className="user-add">
|
<div className="user-add">
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">가맹점 <span className="red">*</span></div>
|
<div className="ua-label">{t('account.merchant')} <span className="red">*</span></div>
|
||||||
<select
|
<select
|
||||||
className="wid-100"
|
className="wid-100"
|
||||||
value={mid}
|
value={mid}
|
||||||
@@ -86,27 +88,27 @@ export const PasswordModifyCancelPasswordPage = () => {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">변경 비밀번호 <span className="red">*</span></div>
|
<div className="ua-label">{t('account.newPassword')} <span className="red">*</span></div>
|
||||||
<input
|
<input
|
||||||
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
|
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="비밀번호를 입력하세요"
|
placeholder={t('account.enterPassword')}
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">변경 비밀번호 재입력 <span className="red">*</span></div>
|
<div className="ua-label">{t('account.reEnterNewPassword')} <span className="red">*</span></div>
|
||||||
<input
|
<input
|
||||||
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
|
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="비밀번호를 다시 입력하세요"
|
placeholder={t('account.reEnterPassword')}
|
||||||
value={confirmPassword}
|
value={confirmPassword}
|
||||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{confirmPassword && password !== confirmPassword && (
|
{confirmPassword && password !== confirmPassword && (
|
||||||
<div className="ua-help error">입력 정보 불일치</div>
|
<div className="ua-help error">{t('account.inputMismatch')}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -116,7 +118,7 @@ export const PasswordModifyCancelPasswordPage = () => {
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={!isFormValid() || changeCancelPasswordMutation.isPending}
|
disabled={!isFormValid() || changeCancelPasswordMutation.isPending}
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
>{changeCancelPasswordMutation.isPending ? '처리중...' : '저장'}</button>
|
>{changeCancelPasswordMutation.isPending ? t('account.processing') : t('common.save')}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { HeaderType } from '@/entities/common/model/types';
|
import { HeaderType } from '@/entities/common/model/types';
|
||||||
@@ -12,6 +13,7 @@ import { useUserChangePasswordMutation } from '@/entities/user/api/use-user-chan
|
|||||||
import { snackBar } from '@/shared/lib/toast';
|
import { snackBar } from '@/shared/lib/toast';
|
||||||
|
|
||||||
export const PasswordModifyLoginPasswordPage = () => {
|
export const PasswordModifyLoginPasswordPage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
const [currentPassword, setCurrentPassword] = useState<string>('');
|
const [currentPassword, setCurrentPassword] = useState<string>('');
|
||||||
const [newPassword, setNewPassword] = useState<string>('');
|
const [newPassword, setNewPassword] = useState<string>('');
|
||||||
@@ -20,7 +22,7 @@ export const PasswordModifyLoginPasswordPage = () => {
|
|||||||
|
|
||||||
const changePasswordMutation = useUserChangePasswordMutation({
|
const changePasswordMutation = useUserChangePasswordMutation({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
snackBar('비밀번호가 성공적으로 변경되었습니다.');
|
snackBar(t('account.passwordChangedSuccessfully'));
|
||||||
// Clear form
|
// Clear form
|
||||||
setCurrentPassword('');
|
setCurrentPassword('');
|
||||||
setNewPassword('');
|
setNewPassword('');
|
||||||
@@ -29,11 +31,11 @@ export const PasswordModifyLoginPasswordPage = () => {
|
|||||||
navigate(PATHS.account.password.manage);
|
navigate(PATHS.account.password.manage);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
|
snackBar(error?.response?.data?.message || t('account.passwordChangeFailed'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
useSetHeaderTitle('로그인 비밀번호 변경');
|
useSetHeaderTitle(t('account.changeLoginPassword'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(false);
|
useSetFooterMode(false);
|
||||||
useSetOnBack(() => {
|
useSetOnBack(() => {
|
||||||
@@ -70,7 +72,7 @@ export const PasswordModifyLoginPasswordPage = () => {
|
|||||||
<div className="ing-list add">
|
<div className="ing-list add">
|
||||||
<div className="user-add">
|
<div className="user-add">
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">기존 비밀번호 <span className="red">*</span></div>
|
<div className="ua-label">{t('account.currentPassword')} <span className="red">*</span></div>
|
||||||
<input
|
<input
|
||||||
className="wid-100"
|
className="wid-100"
|
||||||
type="password"
|
type="password"
|
||||||
@@ -80,7 +82,7 @@ export const PasswordModifyLoginPasswordPage = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">변경 비밀번호 <span className="red">*</span></div>
|
<div className="ua-label">{t('account.newPassword')} <span className="red">*</span></div>
|
||||||
<input
|
<input
|
||||||
className={`wid-100 ${confirmPassword && newPassword !== confirmPassword ? 'error' : ''}`}
|
className={`wid-100 ${confirmPassword && newPassword !== confirmPassword ? 'error' : ''}`}
|
||||||
type="password"
|
type="password"
|
||||||
@@ -90,7 +92,7 @@ export const PasswordModifyLoginPasswordPage = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">변경 비밀번호 재입력 <span className="red">*</span></div>
|
<div className="ua-label">{t('account.reEnterNewPassword')} <span className="red">*</span></div>
|
||||||
<input
|
<input
|
||||||
className={`wid-100 ${confirmPassword && newPassword !== confirmPassword ? 'error' : ''}`}
|
className={`wid-100 ${confirmPassword && newPassword !== confirmPassword ? 'error' : ''}`}
|
||||||
type="password"
|
type="password"
|
||||||
@@ -100,7 +102,7 @@ export const PasswordModifyLoginPasswordPage = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{confirmPassword && newPassword !== confirmPassword && (
|
{confirmPassword && newPassword !== confirmPassword && (
|
||||||
<div className="ua-help error">입력 정보 불일치</div>
|
<div className="ua-help error">{t('account.inputMismatch')}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -110,7 +112,7 @@ export const PasswordModifyLoginPasswordPage = () => {
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={!isFormValid() || changePasswordMutation.isPending}
|
disabled={!isFormValid() || changePasswordMutation.isPending}
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
>{changePasswordMutation.isPending ? '처리중...' : '저장'}</button>
|
>{changePasswordMutation.isPending ? t('account.processing') : t('common.save')}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useLocation } from 'react-router';
|
import { useLocation } from 'react-router';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { AccountUserTab } from '@/entities/account/ui/account-user-tab';
|
import { AccountUserTab } from '@/entities/account/ui/account-user-tab';
|
||||||
@@ -14,12 +15,13 @@ import {
|
|||||||
} from '@/widgets/sub-layout/use-sub-layout';
|
} from '@/widgets/sub-layout/use-sub-layout';
|
||||||
|
|
||||||
export const UserAccountAuthPage = () => {
|
export const UserAccountAuthPage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { mid, usrid, idCL, status } = location.state || {};
|
const { mid, usrid, idCL, status } = location.state || {};
|
||||||
|
|
||||||
const [activeTab, ] = useState<AccountUserTabKeys>(AccountUserTabKeys.AccountAuth);
|
const [activeTab, ] = useState<AccountUserTabKeys>(AccountUserTabKeys.AccountAuth);
|
||||||
useSetHeaderTitle('사용자 설정');
|
useSetHeaderTitle(t('account.userSettings'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(false);
|
useSetFooterMode(false);
|
||||||
useSetOnBack(() => {
|
useSetOnBack(() => {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { HeaderType } from '@/entities/common/model/types';
|
import { HeaderType } from '@/entities/common/model/types';
|
||||||
@@ -15,16 +16,17 @@ import { useLocation } from 'react-router';
|
|||||||
import { snackBar } from '@/shared/lib/toast';
|
import { snackBar } from '@/shared/lib/toast';
|
||||||
|
|
||||||
export const UserAddAccountPage = () => {
|
export const UserAddAccountPage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { mid } = location.state || {};
|
const { mid } = location.state || {};
|
||||||
|
|
||||||
const { mutateAsync: userCreate, isPending } = useUserCreateMutation({
|
const { mutateAsync: userCreate, isPending } = useUserCreateMutation({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
snackBar('사용자가 성공적으로 추가되었습니다.');
|
snackBar(t('account.userAddedSuccessfully'));
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
snackBar(error?.response?.data?.message || '사용자 추가에 실패했습니다.');
|
snackBar(error?.response?.data?.message || t('account.userAddFailed'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -67,13 +69,13 @@ export const UserAddAccountPage = () => {
|
|||||||
if (userExistsData && shouldCheckUsrid) {
|
if (userExistsData && shouldCheckUsrid) {
|
||||||
setIsCheckingUsrid(false);
|
setIsCheckingUsrid(false);
|
||||||
if (userExistsData.exists) {
|
if (userExistsData.exists) {
|
||||||
setErrors(prev => ({ ...prev, usrid: '동일한 ID가 이미 존재합니다.' }));
|
setErrors(prev => ({ ...prev, usrid: t('account.duplicateIdExists') }));
|
||||||
} else {
|
} else {
|
||||||
setErrors(prev => ({ ...prev, usrid: '' }));
|
setErrors(prev => ({ ...prev, usrid: '' }));
|
||||||
}
|
}
|
||||||
setShouldCheckUsrid(false);
|
setShouldCheckUsrid(false);
|
||||||
}
|
}
|
||||||
}, [userExistsData, shouldCheckUsrid]);
|
}, [userExistsData, shouldCheckUsrid, t]);
|
||||||
|
|
||||||
// 이메일/전화번호 관리 함수들 (user-login-auth-info-wrap 방식)
|
// 이메일/전화번호 관리 함수들 (user-login-auth-info-wrap 방식)
|
||||||
const handleAddEmail = () => {
|
const handleAddEmail = () => {
|
||||||
@@ -159,9 +161,9 @@ export const UserAddAccountPage = () => {
|
|||||||
// 비밀번호 검증 함수
|
// 비밀번호 검증 함수
|
||||||
const validatePassword = (password: string) => {
|
const validatePassword = (password: string) => {
|
||||||
if (!password.trim()) {
|
if (!password.trim()) {
|
||||||
return '비밀번호를 입력해 주세요';
|
return t('account.pleaseEnterPassword');
|
||||||
} else if (password.length < 8) {
|
} else if (password.length < 8) {
|
||||||
return '8자리 이상 입력해 주세요';
|
return t('account.pleaseEnter8OrMoreCharacters');
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
@@ -317,16 +319,16 @@ export const UserAddAccountPage = () => {
|
|||||||
|
|
||||||
// 사용자 ID 검증
|
// 사용자 ID 검증
|
||||||
if (!formData.usrid.trim()) {
|
if (!formData.usrid.trim()) {
|
||||||
newErrors.usrid = 'ID를 입력해 주세요';
|
newErrors.usrid = t('account.pleaseEnterId');
|
||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 비밀번호 검증
|
// 비밀번호 검증
|
||||||
if (!formData.password.trim()) {
|
if (!formData.password.trim()) {
|
||||||
newErrors.password = '비밀번호를 입력해 주세요';
|
newErrors.password = t('account.pleaseEnterPassword');
|
||||||
isValid = false;
|
isValid = false;
|
||||||
} else if (formData.password.length < 8) {
|
} else if (formData.password.length < 8) {
|
||||||
newErrors.password = '8자리 이상 입력해 주세요';
|
newErrors.password = t('account.pleaseEnter8OrMoreCharacters');
|
||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,12 +384,12 @@ export const UserAddAccountPage = () => {
|
|||||||
|
|
||||||
if (response.status) {
|
if (response.status) {
|
||||||
// 성공 시 사용자 관리 페이지로 이동
|
// 성공 시 사용자 관리 페이지로 이동
|
||||||
snackBar('사용자가 성공적으로 추가되었습니다.');
|
snackBar(t('account.userAddedSuccessfully'));
|
||||||
navigate(PATHS.account.user.manage);
|
navigate(PATHS.account.user.manage);
|
||||||
} else if (response.error) {
|
} else if (response.error) {
|
||||||
// 에러 처리
|
// 에러 처리
|
||||||
if (response.error.errKey === 'USER_DUPLICATE') {
|
if (response.error.errKey === 'USER_DUPLICATE') {
|
||||||
setErrors(prev => ({ ...prev, usrid: '동일한 ID가 이미 존재합니다.' }));
|
setErrors(prev => ({ ...prev, usrid: t('account.duplicateIdExists') }));
|
||||||
} else {
|
} else {
|
||||||
// 기타 에러 처리
|
// 기타 에러 처리
|
||||||
console.error('User creation failed:', response.error.message);
|
console.error('User creation failed:', response.error.message);
|
||||||
@@ -398,7 +400,7 @@ export const UserAddAccountPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useSetHeaderTitle('사용자 추가');
|
useSetHeaderTitle(t('account.addUser'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(false);
|
useSetFooterMode(false);
|
||||||
useSetOnBack(() => {
|
useSetOnBack(() => {
|
||||||
@@ -413,12 +415,12 @@ export const UserAddAccountPage = () => {
|
|||||||
<div className="ing-list pb-86">
|
<div className="ing-list pb-86">
|
||||||
<div className="user-add">
|
<div className="user-add">
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">사용자ID <span className="red">*</span></div>
|
<div className="ua-label">{t('account.userId')} <span className="red">*</span></div>
|
||||||
<div style={{ position: 'relative' }}>
|
<div style={{ position: 'relative' }}>
|
||||||
<input
|
<input
|
||||||
className={`wid-100 ${errors.usrid ? 'error' : ''}`}
|
className={`wid-100 ${errors.usrid ? 'error' : ''}`}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="ID를 입력해 주세요"
|
placeholder={t('account.pleaseEnterId')}
|
||||||
value={formData.usrid}
|
value={formData.usrid}
|
||||||
onChange={(e) => handleInputChange('usrid', e.target.value)}
|
onChange={(e) => handleInputChange('usrid', e.target.value)}
|
||||||
/>
|
/>
|
||||||
@@ -431,22 +433,22 @@ export const UserAddAccountPage = () => {
|
|||||||
fontSize: '12px',
|
fontSize: '12px',
|
||||||
color: '#666'
|
color: '#666'
|
||||||
}}>
|
}}>
|
||||||
확인 중...
|
{t('account.checking')}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{errors.usrid && <div className="ua-help error pt-10">{errors.usrid}</div>}
|
{errors.usrid && <div className="ua-help error pt-10">{errors.usrid}</div>}
|
||||||
{!errors.usrid && formData.usrid && userExistsData && !userExistsData.exists && (
|
{!errors.usrid && formData.usrid && userExistsData && !userExistsData.exists && (
|
||||||
<div className="ua-help" style={{ color: '#78D197' }}>사용 가능한 ID입니다.</div>
|
<div className="ua-help" style={{ color: '#78D197' }}>{t('account.availableId')}</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">비밀번호 <span className="red">*</span></div>
|
<div className="ua-label">{t('account.password')} <span className="red">*</span></div>
|
||||||
<input
|
<input
|
||||||
className={`wid-100 ${errors.password ? 'error' : ''}`}
|
className={`wid-100 ${errors.password ? 'error' : ''}`}
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="8자리 이상 입력해 주세요"
|
placeholder={t('account.pleaseEnter8OrMoreCharacters')}
|
||||||
value={formData.password}
|
value={formData.password}
|
||||||
onChange={(e) => handleInputChange('password', e.target.value)}
|
onChange={(e) => handleInputChange('password', e.target.value)}
|
||||||
onBlur={handlePasswordBlur}
|
onBlur={handlePasswordBlur}
|
||||||
@@ -455,7 +457,7 @@ export const UserAddAccountPage = () => {
|
|||||||
{errors.password && <div className="ua-help error pt-10">{errors.password}</div>}
|
{errors.password && <div className="ua-help error pt-10">{errors.password}</div>}
|
||||||
|
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">로그인 범위</div>
|
<div className="ua-label">{t('account.loginRange')}</div>
|
||||||
<select
|
<select
|
||||||
className="wid-100"
|
className="wid-100"
|
||||||
value={formData.loginRange}
|
value={formData.loginRange}
|
||||||
@@ -469,17 +471,17 @@ export const UserAddAccountPage = () => {
|
|||||||
<div className="info-divider"></div>
|
<div className="info-divider"></div>
|
||||||
<div className="user-add info">
|
<div className="user-add info">
|
||||||
<div className="ua-desc">
|
<div className="ua-desc">
|
||||||
<div className="ua-title">본인인증용 정보 입력</div>
|
<div className="ua-title">{t('account.identityVerificationInfo')}</div>
|
||||||
<p className="ua-note">입력하신 정보는 이후 로그인 및 가맹점 관련 자료 발송에 이용됩니다.</p>
|
<p className="ua-note">{t('account.identityVerificationNotice')}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="ua-group">
|
<div className="ua-group">
|
||||||
<div className="ua-group-header">
|
<div className="ua-group-header">
|
||||||
<div className="ua-group-title">이메일 주소</div>
|
<div className="ua-group-title">{t('account.emailAddress')}</div>
|
||||||
<button
|
<button
|
||||||
className="ic20 plus"
|
className="ic20 plus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="이메일 추가"
|
aria-label={t('account.addEmail')}
|
||||||
onClick={handleAddEmail}
|
onClick={handleAddEmail}
|
||||||
disabled={!isEmailAddButtonEnabled()}
|
disabled={!isEmailAddButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
@@ -497,7 +499,7 @@ export const UserAddAccountPage = () => {
|
|||||||
<button
|
<button
|
||||||
className="icon-btn minus"
|
className="icon-btn minus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="삭제"
|
aria-label={t('common.delete')}
|
||||||
onClick={() => handleRemoveNewEmail(index)}
|
onClick={() => handleRemoveNewEmail(index)}
|
||||||
disabled={!isDeleteButtonEnabled()}
|
disabled={!isDeleteButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
@@ -507,11 +509,11 @@ export const UserAddAccountPage = () => {
|
|||||||
|
|
||||||
<div className="ua-group">
|
<div className="ua-group">
|
||||||
<div className="ua-group-header">
|
<div className="ua-group-header">
|
||||||
<div className="ua-group-title">휴대폰 번호</div>
|
<div className="ua-group-title">{t('account.phoneNumber')}</div>
|
||||||
<button
|
<button
|
||||||
className="ic20 plus"
|
className="ic20 plus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="휴대폰 추가"
|
aria-label={t('account.addPhone')}
|
||||||
onClick={handleAddPhone}
|
onClick={handleAddPhone}
|
||||||
disabled={!isPhoneAddButtonEnabled()}
|
disabled={!isPhoneAddButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
@@ -529,7 +531,7 @@ export const UserAddAccountPage = () => {
|
|||||||
<button
|
<button
|
||||||
className="icon-btn minus"
|
className="icon-btn minus"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="삭제"
|
aria-label={t('common.delete')}
|
||||||
onClick={() => handleRemoveNewPhone(index)}
|
onClick={() => handleRemoveNewPhone(index)}
|
||||||
disabled={!isDeleteButtonEnabled()}
|
disabled={!isDeleteButtonEnabled()}
|
||||||
></button>
|
></button>
|
||||||
@@ -545,7 +547,7 @@ export const UserAddAccountPage = () => {
|
|||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
disabled={!isSaveButtonEnabled() || isPending}
|
disabled={!isSaveButtonEnabled() || isPending}
|
||||||
>
|
>
|
||||||
{isPending ? '저장 중...' : '저장'}
|
{isPending ? t('common.saving') : t('common.save')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { AccountUserTab } from '@/entities/account/ui/account-user-tab';
|
import { AccountUserTab } from '@/entities/account/ui/account-user-tab';
|
||||||
@@ -14,12 +15,13 @@ import {
|
|||||||
} from '@/widgets/sub-layout/use-sub-layout';
|
} from '@/widgets/sub-layout/use-sub-layout';
|
||||||
|
|
||||||
export const UserLoginAuthInfoPage = () => {
|
export const UserLoginAuthInfoPage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { mid, usrid, idCL, status } = location.state || {};
|
const { mid, usrid, idCL, status } = location.state || {};
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
|
|
||||||
const [activeTab, ] = useState<AccountUserTabKeys>(AccountUserTabKeys.LoginAuthInfo);
|
const [activeTab, ] = useState<AccountUserTabKeys>(AccountUserTabKeys.LoginAuthInfo);
|
||||||
useSetHeaderTitle('사용자 설정');
|
useSetHeaderTitle(t('account.userSettings'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(false);
|
useSetFooterMode(false);
|
||||||
useSetOnBack(() => {
|
useSetOnBack(() => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { AccountTab } from '@/entities/account/ui/account-tab';
|
import { AccountTab } from '@/entities/account/ui/account-tab';
|
||||||
@@ -14,10 +15,11 @@ import {
|
|||||||
} from '@/widgets/sub-layout/use-sub-layout';
|
} from '@/widgets/sub-layout/use-sub-layout';
|
||||||
|
|
||||||
export const UserManagePage = () => {
|
export const UserManagePage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
|
|
||||||
const [activeTab, ] = useState<AccountTabKeys>(AccountTabKeys.UserManage);
|
const [activeTab, ] = useState<AccountTabKeys>(AccountTabKeys.UserManage);
|
||||||
useSetHeaderTitle('계정 관리');
|
useSetHeaderTitle(t('account.title'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(false);
|
useSetFooterMode(false);
|
||||||
useSetOnBack(() => {
|
useSetOnBack(() => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { HeaderType } from '@/entities/common/model/types';
|
import { HeaderType } from '@/entities/common/model/types';
|
||||||
@@ -23,6 +24,7 @@ const PERMISSION = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const UserMenuAuthPage = () => {
|
export const UserMenuAuthPage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { mid, usrid, menuName, subMenu, menuGrants } = location.state || {};
|
const { mid, usrid, menuName, subMenu, menuGrants } = location.state || {};
|
||||||
@@ -35,7 +37,7 @@ export const UserMenuAuthPage = () => {
|
|||||||
const [isInitialLoad, setIsInitialLoad] = useState(true);
|
const [isInitialLoad, setIsInitialLoad] = useState(true);
|
||||||
const savePermissionsMutation = useUserMenuPermissionsSaveMutation({
|
const savePermissionsMutation = useUserMenuPermissionsSaveMutation({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
snackBar('권한이 성공적으로 저장되었습니다.');
|
snackBar(t('account.permissionSavedSuccessfully'));
|
||||||
navigate(PATHS.account.user.accountAuth, {
|
navigate(PATHS.account.user.accountAuth, {
|
||||||
state: {
|
state: {
|
||||||
mid,
|
mid,
|
||||||
@@ -46,7 +48,7 @@ export const UserMenuAuthPage = () => {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
snackBar(error?.response?.data?.message || '권한 저장에 실패했습니다.');
|
snackBar(error?.response?.data?.message || t('account.permissionSaveFailed'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -181,13 +183,13 @@ export const UserMenuAuthPage = () => {
|
|||||||
{ mid, namsUserMenuAccess },
|
{ mid, namsUserMenuAccess },
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
snackBar('권한이 저장되었습니다.');
|
snackBar(t('account.permissionSaved'));
|
||||||
// 저장 성공 후 초기값 업데이트
|
// 저장 성공 후 초기값 업데이트
|
||||||
setInitialPermissions({...permissions});
|
setInitialPermissions({...permissions});
|
||||||
setHasChanges(false);
|
setHasChanges(false);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
alert('권한 저장에 실패했습니다.');
|
alert(t('account.permissionSaveFailed'));
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,8 +202,8 @@ export const UserMenuAuthPage = () => {
|
|||||||
<div className="tab-content">
|
<div className="tab-content">
|
||||||
<div className="tab-pane pt-46 active">
|
<div className="tab-pane pt-46 active">
|
||||||
<div className="ing-list pb-86">
|
<div className="ing-list pb-86">
|
||||||
<div className="desc service-tip">메뉴별 사용 권한을 설정해 주세요.</div>
|
<div className="desc service-tip">{t('account.setMenuPermissions')}</div>
|
||||||
<div className="desc service-tip">선택한 권한에 따라 기능 이용이 제한됩니다.</div>
|
<div className="desc service-tip">{t('account.permissionRestrictionsNotice')}</div>
|
||||||
|
|
||||||
{subMenu && subMenu.map((menu: { menuId: number; menuName: string }) => {
|
{subMenu && subMenu.map((menu: { menuId: number; menuName: string }) => {
|
||||||
const menuGrant = permissions[menu.menuId] || 0;
|
const menuGrant = permissions[menu.menuId] || 0;
|
||||||
@@ -236,7 +238,7 @@ export const UserMenuAuthPage = () => {
|
|||||||
|
|
||||||
{hasDefaultPermission(menu.menuId, PERMISSION.SAVE) && (
|
{hasDefaultPermission(menu.menuId, PERMISSION.SAVE) && (
|
||||||
<div className="settings-row">
|
<div className="settings-row">
|
||||||
<span className="settings-row-title bd-sub dot">저장</span>
|
<span className="settings-row-title bd-sub dot">{t('account.save')}</span>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -250,7 +252,7 @@ export const UserMenuAuthPage = () => {
|
|||||||
|
|
||||||
{hasDefaultPermission(menu.menuId, PERMISSION.EXECUTE) && (
|
{hasDefaultPermission(menu.menuId, PERMISSION.EXECUTE) && (
|
||||||
<div className="settings-row">
|
<div className="settings-row">
|
||||||
<span className="settings-row-title bd-sub dot">실행</span>
|
<span className="settings-row-title bd-sub dot">{t('account.execute')}</span>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -264,7 +266,7 @@ export const UserMenuAuthPage = () => {
|
|||||||
|
|
||||||
{hasDefaultPermission(menu.menuId, PERMISSION.DOWNLOAD) && (
|
{hasDefaultPermission(menu.menuId, PERMISSION.DOWNLOAD) && (
|
||||||
<div className="settings-row">
|
<div className="settings-row">
|
||||||
<span className="settings-row-title bd-sub dot">다운로드</span>
|
<span className="settings-row-title bd-sub dot">{t('account.download')}</span>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -290,7 +292,7 @@ export const UserMenuAuthPage = () => {
|
|||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
disabled={!hasChanges || savePermissionsMutation.isPending}
|
disabled={!hasChanges || savePermissionsMutation.isPending}
|
||||||
>
|
>
|
||||||
{savePermissionsMutation.isPending ? '저장 중...' : '저장'}
|
{savePermissionsMutation.isPending ? t('common.saving') : t('common.save')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user