@smartbooks-ai/layout 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/components/PageWithMenuLayout/AppSelect/index.d.ts +0 -1
  2. package/dist/components/PageWithMenuLayout/AppSelect/index.d.ts.map +1 -1
  3. package/dist/components/PageWithMenuLayout/AppSelect/index.js +2 -2
  4. package/dist/components/PageWithMenuLayout/PageWithMenuLayout.d.ts +0 -1
  5. package/dist/components/PageWithMenuLayout/PageWithMenuLayout.d.ts.map +1 -1
  6. package/dist/components/PageWithMenuLayout/PageWithMenuLayout.js +2 -2
  7. package/dist/index.d.ts +0 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +0 -1
  10. package/dist/theme/colorPrimitives.d.ts +1 -1
  11. package/dist/theme/colorPrimitives.d.ts.map +1 -1
  12. package/dist/theme/index.d.ts.map +1 -1
  13. package/dist/theme/typography.d.ts.map +1 -1
  14. package/package.json +35 -32
  15. package/src/components/PageHeader/PageHeader.tsx +0 -15
  16. package/src/components/PageHeader/index.ts +0 -1
  17. package/src/components/PageHeader/styles.ts +0 -34
  18. package/src/components/PageWithMenuLayout/AppSelect/index.tsx +0 -66
  19. package/src/components/PageWithMenuLayout/AppSelect/styles.ts +0 -33
  20. package/src/components/PageWithMenuLayout/LogoHeaderImage.tsx +0 -44
  21. package/src/components/PageWithMenuLayout/LogoHeaderText.tsx +0 -48
  22. package/src/components/PageWithMenuLayout/MenuItemWithChildren/MenuItemWithChildren.tsx +0 -149
  23. package/src/components/PageWithMenuLayout/MenuItemWithChildren/styles.ts +0 -179
  24. package/src/components/PageWithMenuLayout/MenuSelect/index.tsx +0 -78
  25. package/src/components/PageWithMenuLayout/MenuSelect/styles.ts +0 -97
  26. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/ConsolidationIcon.tsx +0 -6
  27. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/MultiSubscriptionsMenuItems.tsx +0 -120
  28. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/consolidation.svg +0 -8
  29. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/index.ts +0 -1
  30. package/src/components/PageWithMenuLayout/MultiSubscriptionsMenuItems/styles.ts +0 -10
  31. package/src/components/PageWithMenuLayout/PageWithMenuLayout.tsx +0 -103
  32. package/src/components/PageWithMenuLayout/UserProfileSelect/index.tsx +0 -64
  33. package/src/components/PageWithMenuLayout/UserProfileSelect/styles.ts +0 -8
  34. package/src/components/PageWithMenuLayout/index.ts +0 -8
  35. package/src/components/PageWithMenuLayout/styles.ts +0 -110
  36. package/src/components/PageWithMenuLayout/types.ts +0 -7
  37. package/src/components/PageWithMenuLayout/useMenuToggle.ts +0 -19
  38. package/src/components/index.ts +0 -3
  39. package/src/emotion.d.ts +0 -76
  40. package/src/hooks/index.ts +0 -2
  41. package/src/hooks/useIsAuthorized.ts +0 -35
  42. package/src/hooks/useToggle.ts +0 -27
  43. package/src/index.ts +0 -7
  44. package/src/package-isolation.test.ts +0 -60
  45. package/src/security/AuthorizedContent/index.tsx +0 -77
  46. package/src/security/AuthorizedContent/state.ts +0 -8
  47. package/src/security/AuthorizedContent/useAuthorizationState.ts +0 -42
  48. package/src/security/ProfileContext/ProfileContext.tsx +0 -37
  49. package/src/security/ProfileContext/index.ts +0 -4
  50. package/src/security/ProfileContext/types.ts +0 -7
  51. package/src/security/ProfileContext/useProfile.tsx +0 -7
  52. package/src/security/UserProfile.ts +0 -48
  53. package/src/security/index.ts +0 -2
  54. package/src/theme/colorPrimitives.ts +0 -107
  55. package/src/theme/colors.ts +0 -78
  56. package/src/theme/font.ts +0 -27
  57. package/src/theme/globalStyles.tsx +0 -55
  58. package/src/theme/index.tsx +0 -228
  59. package/src/theme/radius.ts +0 -12
  60. package/src/theme/spacing.ts +0 -12
  61. package/src/theme/typography.ts +0 -40
  62. package/src/utils/assertNever.ts +0 -14
  63. package/src/utils/index.ts +0 -2
  64. package/src/utils/shouldNotForwardPropsWithKeys.ts +0 -7
  65. package/tsconfig.json +0 -34
  66. package/tsconfig.layout.tsbuildinfo +0 -1
  67. package/vitest.config.ts +0 -10
@@ -1,110 +0,0 @@
1
- import { css } from '@emotion/react';
2
- import styled from '@emotion/styled';
3
- import MuiDrawer, { drawerClasses } from '@mui/material/Drawer';
4
- import MuiIconButton from '@mui/material/IconButton';
5
- import MenuList from '@mui/material/MenuList';
6
-
7
- import { shouldNotForwardPropsWithKeys } from '../../utils/shouldNotForwardPropsWithKeys';
8
-
9
- const drawerOpenWidthRem = 15.625;
10
- const drawerClosedWidthRem = 3.75;
11
-
12
- export const Drawer = styled(MuiDrawer)`
13
- flex-shrink: 0;
14
-
15
- overflow-x: hidden;
16
- .${drawerClasses.paper} {
17
- width: ${({ open }) => (open ? drawerOpenWidthRem : drawerClosedWidthRem)}rem;
18
-
19
- padding: ${({ theme }) => theme.my.spacing.xs};
20
-
21
- overflow: hidden;
22
-
23
- background-color: ${({ theme }) => theme.my.colors.primary.main};
24
- border: unset;
25
-
26
- transition: width 0.3s;
27
- }
28
- `;
29
-
30
- export const Header = styled.div`
31
- display: flex;
32
-
33
- column-gap: ${({ theme }) => theme.my.spacing.xxs};
34
- align-items: center;
35
-
36
- width: max-content;
37
- min-width: 100%;
38
-
39
- padding-bottom: ${({ theme }) => theme.my.spacing.xs};
40
-
41
- overflow: hidden;
42
- `;
43
-
44
- export const LogoContainer = styled.div`
45
- display: flex;
46
-
47
- align-items: center;
48
- justify-content: center;
49
-
50
- width: 2.25rem;
51
- height: 2.25rem;
52
- `;
53
-
54
- type LockMenuButtonProps = {
55
- isExpanded: boolean;
56
- };
57
- export const LockMenuButton = styled(
58
- MuiIconButton,
59
- shouldNotForwardPropsWithKeys<LockMenuButtonProps>(['isExpanded']),
60
- )<LockMenuButtonProps>(
61
- ({ theme, isExpanded }) => css`
62
- position: absolute;
63
- top: ${theme.my.spacing.sm};
64
- left: ${isExpanded ? drawerOpenWidthRem : drawerClosedWidthRem}rem;
65
- z-index: ${(theme.zIndex?.drawer ?? 0) + 1};
66
-
67
- padding: ${theme.my.spacing.xxxs};
68
-
69
- font-size: 1rem;
70
-
71
- color: ${theme.my.colors.text.white};
72
-
73
- background-color: ${theme.my.colors.primitives.darkNavy[700]};
74
- border-radius: ${theme.my.radius.xxl};
75
-
76
- transform: translateX(-50%) rotate(${isExpanded ? 0 : 180}deg);
77
-
78
- transition: 0.3s;
79
-
80
- &:hover {
81
- background-color: ${theme.my.colors.primitives.darkNavy[600]};
82
- }
83
- `,
84
- );
85
-
86
- export const TopMenuList = styled(MenuList)`
87
- display: flex;
88
-
89
- flex: 1;
90
- flex-direction: column;
91
-
92
- gap: ${({ theme }) => theme.my.spacing.xxxs};
93
-
94
- overflow: hidden auto;
95
- `;
96
-
97
- type MainProps = {
98
- isLocked: boolean;
99
- };
100
- export const Main = styled('div', shouldNotForwardPropsWithKeys<MainProps>(['isLocked']))<MainProps>`
101
- position: relative;
102
-
103
- flex-grow: 1;
104
-
105
- margin-left: ${({ isLocked }) => (isLocked ? drawerOpenWidthRem : drawerClosedWidthRem)}rem;
106
-
107
- overflow: auto;
108
-
109
- transition: margin 0.3s;
110
- `;
@@ -1,7 +0,0 @@
1
- export type MenuItem = {
2
- title: string;
3
- icon?: React.ReactNode;
4
- skipHeader?: boolean;
5
- } & ({ children: MenuItem[] } | { href: string } | { onClick: () => void });
6
-
7
- export type MenuStructure = MenuItem[];
@@ -1,19 +0,0 @@
1
- import { useEffect, useMemo } from 'react';
2
-
3
- import { useProfile, useToggle } from '@smartbooks-ai/layout';
4
-
5
- export const useMenuToggle = () => {
6
- const { value: isExpanded, toggle: toggleIsExpanded, switchOn: openMenu, switchOff: closeMenu } = useToggle(true);
7
-
8
- const { profile } = useProfile();
9
-
10
- const tenants = profile?.allowedTenants;
11
-
12
- const tenantsWithCompanies = useMemo(() => tenants?.filter(({ companies }) => companies.length > 0) ?? [], [tenants]);
13
-
14
- useEffect(() => {
15
- if (tenants && !tenantsWithCompanies.length) closeMenu();
16
- }, [closeMenu, tenants, tenantsWithCompanies.length]);
17
-
18
- return { isExpanded, toggleIsExpanded, openMenu };
19
- };
@@ -1,3 +0,0 @@
1
- export * from './PageWithMenuLayout';
2
- export * from './PageHeader';
3
- export * from './PageWithMenuLayout/types';
package/src/emotion.d.ts DELETED
@@ -1,76 +0,0 @@
1
- import '@emotion/react';
2
- import { ThemeOptions as MuiThemeOptions } from '@mui/material/styles';
3
-
4
- type PaletteShade = 'main' | 'light' | 'dark' | 'contrast';
5
-
6
- type CommonColorShade = '50' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | '950';
7
- type SignalColorShade = '100' | '300' | '600' | '900' | '950';
8
-
9
- type ColorPrimitives = {
10
- darkNavy: Record<CommonColorShade, string>;
11
- coolMint: Record<CommonColorShade, string>;
12
- coral: Record<CommonColorShade, string>;
13
- navy: Record<CommonColorShade, string>;
14
- skyBlue: Record<CommonColorShade, string>;
15
- grey: Record<CommonColorShade, string>;
16
- common: Record<'black' | 'white', string>;
17
- warning: Record<SignalColorShade, string>;
18
- error: Record<SignalColorShade, string>;
19
- success: Record<SignalColorShade, string>;
20
- };
21
-
22
- type ColorPalette = {
23
- primitives: ColorPrimitives;
24
- text: Record<'main' | 'light' | 'lighter' | 'disabled' | 'placeholder' | 'white', string>;
25
- primary: Record<PaletteShade, string>;
26
- secondary: Record<PaletteShade, string>;
27
- tertiary: Record<PaletteShade, string>;
28
- quaternary: Record<PaletteShade, string>;
29
- quinary: Record<PaletteShade, string>;
30
- neutral: Record<PaletteShade, string>;
31
- warning: Record<PaletteShade, string>;
32
- error: Record<PaletteShade, string>;
33
- success: Record<PaletteShade, string>;
34
- background: Record<
35
- 'white' | 'lightGrey' | 'transparent' | 'light' | 'hover' | 'hoverDark' | 'hoverDarkNonTransparent',
36
- string
37
- >;
38
- };
39
-
40
- type FontStyleName =
41
- | 'h1'
42
- | 'h2'
43
- | 'h3'
44
- | 'h4'
45
- | 'h5'
46
- | 'h6'
47
- | 'subtitle1'
48
- | 'subtitle2'
49
- | 'body1'
50
- | 'body2'
51
- | 'body3'
52
- | 'highlight1'
53
- | 'highlight2'
54
- | 'highlight3'
55
- | 'button1'
56
- | 'button2'
57
- | 'caption'
58
- | 'overline'
59
- | 'label'
60
- | 'nav1'
61
- | 'nav2';
62
-
63
- type ThemeOptions = {
64
- my: {
65
- colors: ColorPalette;
66
- spacing: Record<'xxxs' | 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl', string>;
67
- radius: Record<'sq' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'xxxl', string>;
68
- font: Record<FontStyleName, string>;
69
- };
70
- } & MuiThemeOptions;
71
-
72
- declare module '@emotion/react' {
73
- // This declaration is necessary to merge the custom theme with the default theme
74
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/consistent-type-definitions
75
- export interface Theme extends ThemeOptions {}
76
- }
@@ -1,2 +0,0 @@
1
- export { useIsAuthorized } from './useIsAuthorized';
2
- export { useToggle } from './useToggle';
@@ -1,35 +0,0 @@
1
- import { useCallback } from 'react';
2
-
3
- import { CompanyRole, GlobalRole, ResourceType, TenantRole } from '@smartbooks-ai/api-client';
4
-
5
- import { useProfile } from '../security/ProfileContext';
6
-
7
- type AuthorizationParams = {
8
- companyRole?: CompanyRole;
9
- tenantCode?: string;
10
- companyCode?: string;
11
- tenantRole?: TenantRole;
12
- globalRole?: GlobalRole;
13
- resourceType?: ResourceType;
14
- };
15
-
16
- type Output = (params: AuthorizationParams) => boolean | null;
17
-
18
- export const useIsAuthorized = (): Output => {
19
- const { profile } = useProfile();
20
-
21
- return useCallback(
22
- ({ companyCode, companyRole, globalRole, tenantCode, tenantRole, resourceType }) =>
23
- profile &&
24
- (globalRole === undefined || profile.globalRoles.includes(globalRole)) &&
25
- (tenantRole === undefined ||
26
- !!profile.allowedTenants.find(({ code }) => code === tenantCode)?.roles.includes(tenantRole)) &&
27
- (companyRole === undefined ||
28
- !!profile.allowedCompanies.find(({ code }) => code === companyCode)?.roles.includes(companyRole)) &&
29
- (resourceType === undefined ||
30
- !profile.allowedCompanies
31
- .find(({ code }) => code === companyCode)
32
- ?.resources?.find(({ resource }) => resource === resourceType)?.isRestricted),
33
- [profile],
34
- );
35
- };
@@ -1,27 +0,0 @@
1
- import { useCallback, useState } from 'react';
2
-
3
- type Output = {
4
- value: boolean;
5
- switchOn: () => void;
6
- switchOff: () => void;
7
- toggle: () => void;
8
- set: (value: boolean) => void;
9
- };
10
-
11
- export const useToggle = (defaultValue = false): Output => {
12
- const [value, setValue] = useState(defaultValue);
13
-
14
- return {
15
- value,
16
- switchOn: useCallback(() => {
17
- setValue(true);
18
- }, []),
19
- switchOff: useCallback(() => {
20
- setValue(false);
21
- }, []),
22
- toggle: useCallback(() => {
23
- setValue((previous) => !previous);
24
- }, []),
25
- set: setValue,
26
- };
27
- };
package/src/index.ts DELETED
@@ -1,7 +0,0 @@
1
- import './emotion.d.ts';
2
-
3
- export * from './components';
4
- export * from './hooks';
5
- export * from './security';
6
- export * from './theme';
7
- export * from './utils';
@@ -1,60 +0,0 @@
1
- import { glob } from 'glob';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { describe, expect, it } from 'vitest';
5
-
6
- describe('package isolation', () => {
7
- it('should not reference files outside of src folder', async () => {
8
- expect.assertions(1);
9
-
10
- // Find all TypeScript files in src directory
11
- const srcFiles = await glob('src/**/*.{ts,tsx}', {
12
- cwd: path.resolve(__dirname, '..'),
13
- });
14
-
15
- const violations: string[] = [];
16
-
17
- for (const file of srcFiles) {
18
- const filePath = path.resolve(__dirname, '..', file);
19
- const content = fs.readFileSync(filePath, 'utf8');
20
-
21
- // Extract import statements using regex
22
- const importRegex = /^import\s+.*?from\s+['"]([^'"]+)['"]/gm;
23
- let match;
24
-
25
- while ((match = importRegex.exec(content)) !== null) {
26
- const importPath = match[1];
27
-
28
- // Check for relative imports that go outside the src folder
29
- if (importPath.startsWith('../')) {
30
- const resolvedPath = path.resolve(path.dirname(filePath), importPath);
31
- const srcRoot = path.resolve(__dirname, '..', 'src');
32
-
33
- // Only flag as violation if the resolved path is outside the src folder
34
- if (!resolvedPath.startsWith(srcRoot + path.sep) && resolvedPath !== srcRoot) {
35
- violations.push(`${file}: ${importPath}`);
36
- }
37
- }
38
- }
39
-
40
- // Also check for dynamic imports that go outside the src folder
41
- const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
42
- while ((match = dynamicImportRegex.exec(content)) !== null) {
43
- const importPath = match[1];
44
-
45
- if (importPath.startsWith('../')) {
46
- const resolvedPath = path.resolve(path.dirname(filePath), importPath);
47
- const srcRoot = path.resolve(__dirname, '..', 'src');
48
-
49
- if (!resolvedPath.startsWith(srcRoot + path.sep) && resolvedPath !== srcRoot) {
50
- violations.push(`${file}: ${importPath} (dynamic import)`);
51
- }
52
- }
53
- }
54
- }
55
-
56
- console.log(violations);
57
-
58
- expect(violations).toHaveLength(0);
59
- });
60
- });
@@ -1,77 +0,0 @@
1
- import { JSX, useEffect } from 'react';
2
-
3
- import { CompanyRole, GlobalRole, TenantRole } from '@smartbooks-ai/api-client';
4
-
5
- import { State } from './state';
6
- import { useAuthorizationState } from './useAuthorizationState';
7
-
8
- import { ProfileState, useProfile } from '../../security/ProfileContext';
9
- import { assertNever } from '../../utils/assertNever';
10
-
11
- type Props = {
12
- requireCompanyRole?: CompanyRole;
13
- requireTenantRole?: TenantRole;
14
- requireGlobalRole?: GlobalRole;
15
- companyCode?: string;
16
- tenantCode?: string;
17
- children?: React.ReactNode;
18
- errorElement?: JSX.Element;
19
- loadingElement?: JSX.Element;
20
- notLoggedInElement?: JSX.Element;
21
- unauthorizedElement?: React.ReactNode;
22
- shouldInitiateLogin?: boolean;
23
- };
24
-
25
- const AuthorizedContent: React.FC<Props> = ({
26
- children,
27
- companyCode,
28
- errorElement,
29
- shouldInitiateLogin,
30
- loadingElement,
31
- notLoggedInElement,
32
- requireCompanyRole,
33
- requireGlobalRole,
34
- requireTenantRole,
35
- tenantCode,
36
- unauthorizedElement,
37
- }) => {
38
- const { state, initiateLogin } = useProfile();
39
-
40
- const authorizationState = useAuthorizationState({
41
- companyCode,
42
- companyRole: requireCompanyRole,
43
- globalRole: requireGlobalRole,
44
- tenantCode,
45
- tenantRole: requireTenantRole,
46
- });
47
-
48
- useEffect(() => {
49
- if (state === ProfileState.notLoggedIn && shouldInitiateLogin) {
50
- initiateLogin();
51
- }
52
- }, [initiateLogin, shouldInitiateLogin, state]);
53
-
54
- useEffect(() => {
55
- if (authorizationState === State.needsProfileLinking) {
56
- window.location.href = '/link-identities'; // Cannot use navigate outside of a RouterContext
57
- }
58
- }, [authorizationState]);
59
-
60
- switch (authorizationState) {
61
- case State.loading:
62
- case State.needsProfileLinking:
63
- return loadingElement;
64
- case State.authorized:
65
- return children;
66
- case State.notLoggedIn:
67
- return notLoggedInElement;
68
- case State.unauthorized:
69
- return unauthorizedElement;
70
- case State.error:
71
- return errorElement;
72
- default:
73
- return assertNever(authorizationState);
74
- }
75
- };
76
-
77
- export { AuthorizedContent };
@@ -1,8 +0,0 @@
1
- export enum State {
2
- loading,
3
- authorized,
4
- unauthorized,
5
- error,
6
- notLoggedIn,
7
- needsProfileLinking,
8
- }
@@ -1,42 +0,0 @@
1
- import { CompanyRole, GlobalRole, TenantRole } from '@smartbooks-ai/api-client';
2
-
3
- import { State } from './state';
4
-
5
- import { useIsAuthorized } from '../../hooks/useIsAuthorized';
6
- import { ProfileState, useProfile } from '../../security/ProfileContext';
7
-
8
- type Input = {
9
- companyRole?: CompanyRole;
10
- tenantCode?: string;
11
- companyCode?: string;
12
- tenantRole?: TenantRole;
13
- globalRole?: GlobalRole;
14
- };
15
-
16
- export const useAuthorizationState = ({
17
- companyCode,
18
- companyRole,
19
- globalRole,
20
- tenantCode,
21
- tenantRole,
22
- }: Input): State => {
23
- const { profile, state } = useProfile();
24
-
25
- const getIsAuthorized = useIsAuthorized();
26
-
27
- if (profile) {
28
- return getIsAuthorized({ companyCode, companyRole, globalRole, tenantCode, tenantRole })
29
- ? State.authorized
30
- : State.unauthorized;
31
- }
32
- switch (state) {
33
- case ProfileState.notLoggedIn:
34
- return State.notLoggedIn;
35
- case ProfileState.loading:
36
- return State.loading;
37
- case ProfileState.needsLinking:
38
- return State.needsProfileLinking;
39
- default:
40
- return State.error;
41
- }
42
- };
@@ -1,37 +0,0 @@
1
- import { createContext } from 'react';
2
-
3
- import { ProfileState } from './types';
4
-
5
- import { UserProfile } from '../UserProfile';
6
-
7
- export type InitiateLoginArgs = {
8
- forceSignUp?: boolean;
9
- forceSignIn?: boolean;
10
- returnTo?: string;
11
- loginHint?: string;
12
- connection?: string;
13
- };
14
-
15
- export type PrimaryProfileInformation = {
16
- connection: string;
17
- canUseLoginHint: boolean;
18
- };
19
-
20
- export type ProfileContextValue = {
21
- profile: UserProfile | null;
22
- state: ProfileState;
23
- primaryProfileInformation?: PrimaryProfileInformation;
24
- initiateLogin: (args?: InitiateLoginArgs) => void;
25
- reload: () => void;
26
- };
27
-
28
- const unsetFn = () => {
29
- throw new Error('Unable interact before initializing the profile provider');
30
- };
31
-
32
- export const ProfileContext = createContext<ProfileContextValue>({
33
- profile: null,
34
- state: ProfileState.loading,
35
- initiateLogin: unsetFn,
36
- reload: unsetFn,
37
- });
@@ -1,4 +0,0 @@
1
- export { UserProfile } from '../UserProfile';
2
- export { useProfile } from './useProfile';
3
- export { ProfileState } from './types';
4
- export * from './ProfileContext';
@@ -1,7 +0,0 @@
1
- export enum ProfileState {
2
- loading,
3
- loaded,
4
- notLoggedIn,
5
- error,
6
- needsLinking,
7
- }
@@ -1,7 +0,0 @@
1
- import { useContext } from 'react';
2
-
3
- import { ProfileContext } from './ProfileContext';
4
-
5
- export function useProfile() {
6
- return useContext(ProfileContext);
7
- }
@@ -1,48 +0,0 @@
1
- import { AvailableCompany, AvailableTenant, GlobalRole, Profile } from '@smartbooks-ai/api-client';
2
-
3
- export class UserProfile {
4
- displayName: string;
5
- email: string;
6
- allowedTenants: AvailableTenant[];
7
- allowedCompanies: AvailableCompany[];
8
- globalRoles: GlobalRole[];
9
- userId: string;
10
-
11
- constructor(
12
- userId: string,
13
- displayName: string,
14
- email: string,
15
- allowedTenants: AvailableTenant[],
16
- globalRoles: GlobalRole[],
17
- ) {
18
- this.userId = userId;
19
- this.displayName = displayName;
20
- this.email = email;
21
- this.allowedTenants = allowedTenants;
22
- this.globalRoles = globalRoles;
23
- this.allowedCompanies = allowedTenants
24
- .flatMap((t) => t.companies)
25
- .sort((a, b) => a.description.localeCompare(b.description));
26
- }
27
-
28
- public static create(
29
- given_name: string | undefined,
30
- family_name: string | undefined,
31
- email_address: string | undefined,
32
- profileResponse: Profile,
33
- ) {
34
- const firstName = given_name;
35
- const lastName = family_name;
36
- const email = email_address || 'Email Unknown';
37
-
38
- const displayName = firstName || lastName ? `${firstName} ${lastName}`.trim() : email;
39
-
40
- return new UserProfile(
41
- profileResponse.userId,
42
- displayName,
43
- email,
44
- profileResponse.tenants,
45
- profileResponse.globalRoles,
46
- );
47
- }
48
- }
@@ -1,2 +0,0 @@
1
- export * from './ProfileContext';
2
- export * from './AuthorizedContent';