forked from baron/baron-sso
네이버 계정 정합성 맞춤
This commit is contained in:
@@ -61,6 +61,13 @@ function TenantCreatePage() {
|
||||
});
|
||||
const tenants = parentQuery.data?.items ?? [];
|
||||
const selectedParentTenant = tenants.find((tenant) => tenant.id === parentId);
|
||||
const hanmacFamilyTenantId = useMemo(
|
||||
() =>
|
||||
tenants.find(
|
||||
(tenant) => tenant.slug.trim().toLowerCase() === "hanmac-family",
|
||||
)?.id ?? "",
|
||||
[tenants],
|
||||
);
|
||||
const canConfigureHanmacOrg = useMemo(() => {
|
||||
if (!selectedParentTenant) return false;
|
||||
if (selectedParentTenant.slug.toLowerCase() === "hanmac-family") {
|
||||
@@ -206,6 +213,7 @@ function TenantCreatePage() {
|
||||
"ui.admin.tenants.create.form.pick_hanmac_parent",
|
||||
"한맥가족에서 선택",
|
||||
)}
|
||||
orgChartTenantId={hanmacFamilyTenantId}
|
||||
localPickerLabel={t(
|
||||
"ui.admin.tenants.create.form.pick_other_parent",
|
||||
"다른 테넌트 선택",
|
||||
|
||||
@@ -125,7 +125,7 @@ function TenantDetailPage() {
|
||||
</div>
|
||||
|
||||
{/* Outlet for nested routes */}
|
||||
<div className="animate-in fade-in duration-500">
|
||||
<div>
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildWorksmobilePasswordManageUrl,
|
||||
@@ -28,6 +30,18 @@ import {
|
||||
} from "./worksmobileComparison";
|
||||
|
||||
describe("TenantWorksmobilePage comparison helpers", () => {
|
||||
it("does not apply page-level enter animations to Worksmobile tab panels", () => {
|
||||
const source = readFileSync(
|
||||
join(
|
||||
process.cwd(),
|
||||
"src/features/tenants/routes/TenantWorksmobilePage.tsx",
|
||||
),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
expect(source).not.toContain("space-y-4 animate-in fade-in duration-500");
|
||||
});
|
||||
|
||||
it("summarizes comparison rows by status", () => {
|
||||
const summary = summarizeWorksmobileComparison([
|
||||
{ resourceType: "USER", status: "matched" },
|
||||
@@ -594,6 +608,41 @@ describe("TenantWorksmobilePage comparison helpers", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("formats backend update reasons when value diff details are not directly visible", () => {
|
||||
expect(
|
||||
formatWorksmobileUpdateDetails({
|
||||
resourceType: "USER",
|
||||
status: "needs_update",
|
||||
baronId: "user-1",
|
||||
baronName: "신현우",
|
||||
worksmobileName: "신현우",
|
||||
baronEmail: "hwshin2@hanmaceng.co.kr",
|
||||
worksmobileEmail: "hwshin2@hanmaceng.co.kr",
|
||||
externalKey: "user-1",
|
||||
updateReasons: ["organization"],
|
||||
}),
|
||||
).toEqual(["조직: Baron 소속 정보를 WORKS에 반영해야 합니다."]);
|
||||
});
|
||||
|
||||
it("does not format phone update details for spaced Korean country code formatting only", () => {
|
||||
expect(
|
||||
formatWorksmobileUpdateDetails({
|
||||
resourceType: "USER",
|
||||
status: "needs_update",
|
||||
baronId: "user-1",
|
||||
baronName: "강명진",
|
||||
worksmobileName: "강명진",
|
||||
baronEmail: "mjkang4@hanmaceng.co.kr",
|
||||
worksmobileEmail: "mjkang4@hanmaceng.co.kr",
|
||||
externalKey: "user-1",
|
||||
baronPhone: "+821041585840",
|
||||
worksmobilePhone: "+82 1041585840",
|
||||
baronEmployeeNumber: "mjkang4",
|
||||
worksmobileEmployeeNumber: "M17205",
|
||||
}),
|
||||
).toEqual(["사번: M17205 -> mjkang4"]);
|
||||
});
|
||||
|
||||
it("formats WORKS account name with level on one line", () => {
|
||||
expect(
|
||||
formatWorksmobilePersonName({
|
||||
|
||||
@@ -520,7 +520,7 @@ export function TenantWorksmobilePage() {
|
||||
</div>
|
||||
|
||||
{activeTab === "history" ? (
|
||||
<div className="space-y-4 animate-in fade-in duration-500">
|
||||
<div className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between gap-3">
|
||||
<div>
|
||||
@@ -627,7 +627,7 @@ export function TenantWorksmobilePage() {
|
||||
) : null}
|
||||
|
||||
{activeTab === "users" ? (
|
||||
<div className="space-y-4 animate-in fade-in duration-500">
|
||||
<div className="space-y-4">
|
||||
<ComparisonSummary
|
||||
title={t(
|
||||
"ui.admin.tenants.worksmobile.compare",
|
||||
@@ -715,7 +715,7 @@ export function TenantWorksmobilePage() {
|
||||
) : null}
|
||||
|
||||
{activeTab === "groups" ? (
|
||||
<div className="space-y-4 animate-in fade-in duration-500">
|
||||
<div className="space-y-4">
|
||||
<ComparisonSummary
|
||||
title={t(
|
||||
"ui.admin.tenants.worksmobile.compare_groups",
|
||||
|
||||
@@ -374,28 +374,39 @@ export function formatWorksmobileUpdateDetails(row: WorksmobileComparisonItem) {
|
||||
}
|
||||
|
||||
const details: string[] = [];
|
||||
const renderedReasons = new Set<string>();
|
||||
const addDetail = (reason: string, detail: string) => {
|
||||
details.push(detail);
|
||||
renderedReasons.add(reason);
|
||||
};
|
||||
const baronName = row.baronName?.trim();
|
||||
const worksmobileName = row.worksmobileName?.trim();
|
||||
if (baronName && worksmobileName && baronName !== worksmobileName) {
|
||||
details.push(`이름: ${worksmobileName} -> ${baronName}`);
|
||||
addDetail("name", `이름: ${worksmobileName} -> ${baronName}`);
|
||||
}
|
||||
if (row.resourceType === "USER") {
|
||||
const expectedExternalKey = row.baronId?.trim() ?? "";
|
||||
const actualExternalKey = row.externalKey?.trim() ?? "";
|
||||
if (expectedExternalKey && expectedExternalKey !== actualExternalKey) {
|
||||
details.push(
|
||||
addDetail(
|
||||
"external_key",
|
||||
`external_key: ${actualExternalKey || "없음"} -> ${expectedExternalKey}`,
|
||||
);
|
||||
}
|
||||
const expectedEmail = row.baronEmail?.trim().toLowerCase() ?? "";
|
||||
const actualEmail = row.worksmobileEmail?.trim().toLowerCase() ?? "";
|
||||
if (expectedEmail && actualEmail && expectedEmail !== actualEmail) {
|
||||
details.push(`이메일: ${actualEmail} -> ${expectedEmail}`);
|
||||
addDetail("email", `이메일: ${actualEmail} -> ${expectedEmail}`);
|
||||
}
|
||||
const expectedPhone = row.baronPhone?.trim() ?? "";
|
||||
const actualPhone = row.worksmobilePhone?.trim() ?? "";
|
||||
if (expectedPhone && actualPhone && expectedPhone !== actualPhone) {
|
||||
details.push(`전화번호: ${actualPhone} -> ${expectedPhone}`);
|
||||
if (
|
||||
expectedPhone &&
|
||||
actualPhone &&
|
||||
normalizeWorksmobilePhoneForCompare(expectedPhone) !==
|
||||
normalizeWorksmobilePhoneForCompare(actualPhone)
|
||||
) {
|
||||
addDetail("phone", `전화번호: ${actualPhone} -> ${expectedPhone}`);
|
||||
}
|
||||
const expectedEmployeeNumber = row.baronEmployeeNumber?.trim() ?? "";
|
||||
const actualEmployeeNumber = row.worksmobileEmployeeNumber?.trim() ?? "";
|
||||
@@ -404,10 +415,12 @@ export function formatWorksmobileUpdateDetails(row: WorksmobileComparisonItem) {
|
||||
actualEmployeeNumber &&
|
||||
expectedEmployeeNumber !== actualEmployeeNumber
|
||||
) {
|
||||
details.push(
|
||||
addDetail(
|
||||
"employee_number",
|
||||
`사번: ${actualEmployeeNumber} -> ${expectedEmployeeNumber}`,
|
||||
);
|
||||
}
|
||||
appendWorksmobileUpdateReasonFallbacks(details, row, renderedReasons);
|
||||
return details;
|
||||
}
|
||||
|
||||
@@ -427,14 +440,86 @@ export function formatWorksmobileUpdateDetails(row: WorksmobileComparisonItem) {
|
||||
const actualParentKey =
|
||||
row.worksmobileParentId ?? row.worksmobileParentExternalKey ?? "";
|
||||
if (expectedParentKey !== actualParentKey) {
|
||||
details.push(
|
||||
addDetail(
|
||||
"organization",
|
||||
`상위: ${actualParent || "없음"} -> ${expectedParent || "없음"}`,
|
||||
);
|
||||
}
|
||||
|
||||
appendWorksmobileUpdateReasonFallbacks(details, row, renderedReasons);
|
||||
return details;
|
||||
}
|
||||
|
||||
function appendWorksmobileUpdateReasonFallbacks(
|
||||
details: string[],
|
||||
row: WorksmobileComparisonItem,
|
||||
renderedReasons: Set<string>,
|
||||
) {
|
||||
for (const reason of row.updateReasons ?? []) {
|
||||
const normalizedReason = reason.trim();
|
||||
if (!normalizedReason || renderedReasons.has(normalizedReason)) {
|
||||
continue;
|
||||
}
|
||||
const detail = formatWorksmobileUpdateReasonFallback(normalizedReason, row);
|
||||
if (!detail) {
|
||||
continue;
|
||||
}
|
||||
details.push(detail);
|
||||
renderedReasons.add(normalizedReason);
|
||||
}
|
||||
}
|
||||
|
||||
function formatWorksmobileUpdateReasonFallback(
|
||||
reason: string,
|
||||
row: WorksmobileComparisonItem,
|
||||
) {
|
||||
switch (reason) {
|
||||
case "name":
|
||||
return "이름: Baron 사용자명을 WORKS에 반영해야 합니다.";
|
||||
case "external_key":
|
||||
return "external_key: Baron 사용자 ID를 WORKS 외부 키로 반영해야 합니다.";
|
||||
case "email":
|
||||
return "이메일: Baron 이메일을 WORKS에 반영해야 합니다.";
|
||||
case "phone":
|
||||
return "전화번호: Baron 전화번호를 WORKS에 반영해야 합니다.";
|
||||
case "employee_number":
|
||||
return "사번: Baron 사번을 WORKS에 반영해야 합니다.";
|
||||
case "organization":
|
||||
return row.resourceType === "GROUP"
|
||||
? "조직: Baron 조직 정보를 WORKS에 반영해야 합니다."
|
||||
: "조직: Baron 소속 정보를 WORKS에 반영해야 합니다.";
|
||||
case "manager":
|
||||
return "조직장: Baron 조직장 설정을 WORKS에 반영해야 합니다.";
|
||||
default:
|
||||
return `업데이트 사유: ${reason}`;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeWorksmobilePhoneForCompare(value: string) {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) {
|
||||
return "";
|
||||
}
|
||||
const digits = trimmed.replace(/\D/g, "");
|
||||
if (!digits) {
|
||||
return "";
|
||||
}
|
||||
if (digits.startsWith("010")) {
|
||||
return `+82${digits.slice(1)}`;
|
||||
}
|
||||
if (digits.startsWith("82")) {
|
||||
let rest = digits.slice(2);
|
||||
while (rest.startsWith("82")) {
|
||||
rest = rest.slice(2);
|
||||
}
|
||||
if (rest.startsWith("0")) {
|
||||
rest = rest.slice(1);
|
||||
}
|
||||
return `+82${rest}`;
|
||||
}
|
||||
return `+${digits}`;
|
||||
}
|
||||
|
||||
export function buildWorksmobilePasswordManageUrl({
|
||||
tenantId,
|
||||
domainId,
|
||||
|
||||
Reference in New Issue
Block a user