1
0
forked from baron/baron-sso

chore: snapshot local state before dev merge

This commit is contained in:
2026-06-17 21:25:42 +09:00
parent b2808759d2
commit 49560e8a8c
107 changed files with 8958 additions and 939 deletions

View File

@@ -7,6 +7,8 @@ export type OrgChartUserSelection = {
id: string;
name: string;
email: string;
rootTenantName?: string;
leafTenantName?: string;
};
export type TenantFilterTarget = {
@@ -30,6 +32,20 @@ export type HanmacFamilyUserTarget = {
metadata?: Record<string, unknown>;
};
export type UserMembershipTenantTabId =
| "hanmac-family"
| "commercial"
| "public-org"
| "edu"
| "personal";
export type UserMembershipTenantTab = {
id: UserMembershipTenantTabId;
label: string;
rootSlug: string;
seedTenantId?: string;
};
type OrgChartPickerMessage = {
type?: unknown;
payload?: {
@@ -38,6 +54,9 @@ type OrgChartPickerMessage = {
id?: unknown;
name?: unknown;
email?: unknown;
rootTenantName?: unknown;
leafTenantName?: unknown;
tenantName?: unknown;
}>;
};
};
@@ -47,6 +66,10 @@ type OrgChartTenantPickerOptions = {
tenantId?: string;
};
type OrgChartUserMultiPickerOptions = {
tenantId?: string;
};
type OrgChartLoginOptions = {
includeInternal?: boolean;
returnTo?: string;
@@ -54,6 +77,36 @@ type OrgChartLoginOptions = {
const DEFAULT_ORGFRONT_BASE_URL = "http://localhost:5175";
export const USER_MEMBERSHIP_TENANT_TABS: UserMembershipTenantTab[] = [
{
id: "hanmac-family",
label: "한맥가족",
rootSlug: "hanmac-family",
seedTenantId: "038326b6-954a-48a7-a85f-efd83f62b82a",
},
{
id: "commercial",
label: "일반회사",
rootSlug: "commercial",
},
{
id: "public-org",
label: "공공기관",
rootSlug: "public-org",
},
{
id: "edu",
label: "교육기관",
rootSlug: "edu",
},
{
id: "personal",
label: "개인",
rootSlug: "personal",
seedTenantId: "9607eb7b-04d2-42ab-80fe-780fe21c7e8f",
},
];
export const GPDTDC_GRADE_OPTIONS = [
"연구원",
"선임",
@@ -70,8 +123,8 @@ export const HANMAC_FAMILY_GRADE_OPTIONS = [
"차장",
"부장",
"이사",
"상무",
"전무",
"상무이사",
"전무이사",
"부사장",
"사장",
"회장",
@@ -108,6 +161,118 @@ function resolveTenantTarget<T extends TenantFilterTarget>(
);
}
function resolveMembershipRoot<T extends TenantFilterTarget>(
tab: UserMembershipTenantTab,
tenants: T[],
) {
const rootSlug = tab.rootSlug.toLowerCase();
return (
tenants.find(
(tenant) => tab.seedTenantId && tenant.id === tab.seedTenantId,
) ??
tenants.find((tenant) => tenant.slug?.trim().toLowerCase() === rootSlug)
);
}
export function classifyTenantByMembershipRoot<T extends TenantFilterTarget>(
target: TenantFilterTarget | undefined,
tenants: T[],
) {
const tenant = resolveTenantTarget(target, tenants);
if (!tenant?.id) return undefined;
const tenantById = new Map(
tenants
.filter((item) => item.id?.trim())
.map((item) => [item.id as string, item]),
);
return USER_MEMBERSHIP_TENANT_TABS.find((tab) => {
const root = resolveMembershipRoot(tab, tenants);
if (!root?.id) return false;
const resolvedTenant = tenantById.get(tenant.id ?? "") ?? tenant;
return isInTenantSubtree(resolvedTenant, root.id, tenantById);
});
}
export function filterTenantsByMembershipRoot<T extends TenantFilterTarget>(
tenants: T[],
tabId: UserMembershipTenantTabId,
) {
const tab = USER_MEMBERSHIP_TENANT_TABS.find((item) => item.id === tabId);
if (!tab) return [];
const root = resolveMembershipRoot(tab, tenants);
if (!root?.id) return [];
const tenantById = new Map(
tenants
.filter((tenant) => tenant.id?.trim())
.map((tenant) => [tenant.id as string, tenant]),
);
return tenants.filter(
(tenant) =>
!isSystemTenant(tenant) &&
isPublicRepresentativeTenant(tenant) &&
isInTenantSubtree(tenant, root.id as string, tenantById),
);
}
export function resolveUserMembershipTenantTab<T extends TenantFilterTarget>(
user: HanmacFamilyUserTarget,
tenants: T[],
) {
const metadataAppointments = Array.isArray(
user.metadata?.additionalAppointments,
)
? user.metadata.additionalAppointments
.map((appointment) => appointment as TenantFilterTarget)
.filter(
(appointment) =>
typeof appointment.tenantId === "string" ||
typeof appointment.id === "string" ||
typeof appointment.tenantSlug === "string" ||
typeof appointment.slug === "string",
)
.map((appointment) => ({
id: appointment.id ?? appointment.tenantId,
slug: appointment.slug ?? appointment.tenantSlug,
parentId: appointment.parentId,
type: appointment.type,
name: appointment.name ?? appointment.tenantName,
}))
: [];
const tenantBySlug = new Map(
tenants
.filter((tenant) => tenant.slug?.trim())
.map((tenant) => [tenant.slug?.toLowerCase() as string, tenant]),
);
const tenantById = new Map(
tenants
.filter((tenant) => tenant.id?.trim())
.map((tenant) => [tenant.id as string, tenant]),
);
const candidates = [
user.tenant,
...(user.joinedTenants ?? []),
...metadataAppointments,
...metadataAppointments.map((appointment) =>
tenantById.get(appointment.id ?? ""),
),
tenantBySlug.get(user.tenantSlug?.toLowerCase() ?? ""),
];
return (
USER_MEMBERSHIP_TENANT_TABS.find((tab) =>
candidates.some(
(candidate) =>
classifyTenantByMembershipRoot(candidate, tenants)?.id === tab.id,
),
) ?? USER_MEMBERSHIP_TENANT_TABS[0]
);
}
function isGPDTDCTenant<T extends TenantFilterTarget>(
target: TenantFilterTarget | undefined,
tenants: T[],
@@ -326,7 +491,10 @@ export function buildAuthenticatedOrgChartTenantPickerUrl(
return buildAuthenticatedOrgChartUrl(baseUrl, { returnTo: pickerUrl });
}
export function buildOrgChartUserMultiPickerUrl(baseUrl?: string) {
export function buildOrgChartUserMultiPickerUrl(
baseUrl?: string,
options: OrgChartUserMultiPickerOptions = {},
) {
const normalizedBase = (baseUrl ?? "").replace(/\/+$/, "");
const params = new URLSearchParams({
mode: "multiple",
@@ -337,12 +505,18 @@ export function buildOrgChartUserMultiPickerUrl(baseUrl?: string) {
params.set("includeInternal", "true");
params.set("includeDescendants", "true");
params.set("showDescendantToggle", "true");
if (options.tenantId?.trim()) {
params.set("tenantId", options.tenantId.trim());
}
return `${normalizedBase}/embed/picker?${params.toString()}`;
}
export function buildAuthenticatedOrgChartUserMultiPickerUrl(baseUrl?: string) {
const pickerUrl = buildOrgChartUserMultiPickerUrl("");
export function buildAuthenticatedOrgChartUserMultiPickerUrl(
baseUrl?: string,
options: OrgChartUserMultiPickerOptions = {},
) {
const pickerUrl = buildOrgChartUserMultiPickerUrl("", options);
return buildAuthenticatedOrgChartUrl(baseUrl, { returnTo: pickerUrl });
}
@@ -418,5 +592,15 @@ export function parseOrgChartUserSelections(
id: selection.id,
name: selection.name,
email: typeof selection.email === "string" ? selection.email : "",
rootTenantName:
typeof selection.rootTenantName === "string"
? selection.rootTenantName
: undefined,
leafTenantName:
typeof selection.leafTenantName === "string"
? selection.leafTenantName
: typeof selection.tenantName === "string"
? selection.tenantName
: undefined,
}));
}