diff --git a/frontend/src/lib/components/TenantUsersList/TenantUsersList.svelte b/frontend/src/lib/components/TenantUsersList/TenantUsersList.svelte new file mode 100644 index 0000000..5a01366 --- /dev/null +++ b/frontend/src/lib/components/TenantUsersList/TenantUsersList.svelte @@ -0,0 +1,41 @@ + + + + + + + + {#each tenantUsers as user} + + {user.firstName + ' ' + user.lastName} + {user.email} + + {/each} + +
+
+
diff --git a/frontend/src/lib/components/Tenants/Tenants.svelte b/frontend/src/lib/components/Tenants/Tenants.svelte index acdfc1e..6dc94fe 100644 --- a/frontend/src/lib/components/Tenants/Tenants.svelte +++ b/frontend/src/lib/components/Tenants/Tenants.svelte @@ -1,19 +1,18 @@ {#if tenants} -
- - {#each tenants as tenant} - - - - {/each} - -
+ + {#each tenants as tenant} + + + + {/each} + {/if} diff --git a/frontend/src/lib/context/TenantUsersContext/TenantUsers.ts b/frontend/src/lib/context/TenantUsersContext/TenantUsers.ts new file mode 100644 index 0000000..ac837ae --- /dev/null +++ b/frontend/src/lib/context/TenantUsersContext/TenantUsers.ts @@ -0,0 +1,14 @@ +import { z } from 'zod'; + +// const StatusSchema = z.union([z.literal('ENABLED'), z.literal('DISABLED')]); + +export const TenantUserSchema = z.object({ + id: z.number(), + email: z.string(), + // password: z.string(), + // status: StatusSchema, + firstName: z.string(), + lastName: z.string() +}); + +export type TenantUser = z.infer; diff --git a/frontend/src/lib/context/UnityAuthContext.ts b/frontend/src/lib/context/UnityAuthContext.ts index 365e121..4d3975e 100644 --- a/frontend/src/lib/context/UnityAuthContext.ts +++ b/frontend/src/lib/context/UnityAuthContext.ts @@ -39,9 +39,12 @@ export function createUnityAuthContext(props: UnityAuthContextProviderProps & Un ...props.unityAuthServiceProps }); + unityAuthService.setAuthInfo(unityAuthService.getLoginData()); const user: Writable = writable(unityAuthService.getLoginData()); unityAuthService.subscribe('login', (args) => user.set(args)); unityAuthService.subscribe('logout', () => user.set(undefined)); + unityAuthService.subscribe('login', (args) => unityAuthService.setAuthInfo(args)); + unityAuthService.subscribe('logout', () => unityAuthService.setAuthInfo(undefined)); function alertError(unknown: unknown) { console.error(unknown); diff --git a/frontend/src/lib/services/TenantsResolver/shared.ts b/frontend/src/lib/services/TenantsResolver/shared.ts index dc2a763..61748d9 100644 --- a/frontend/src/lib/services/TenantsResolver/shared.ts +++ b/frontend/src/lib/services/TenantsResolver/shared.ts @@ -1,13 +1,13 @@ import { z } from 'zod'; -export const TenantsSchema = z.object({ +export const TenantSchema = z.object({ id: z.number(), name: z.string() }); -export type Tenants = z.infer; +export type Tenant = z.infer; -export const TenantsSuccessResponseSchema = z.array(TenantsSchema); +export const TenantsSuccessResponseSchema = z.array(TenantSchema); export type TenantsSuccessResponse = z.infer; diff --git a/frontend/src/lib/services/UnityAuth/UnityAuth.ts b/frontend/src/lib/services/UnityAuth/UnityAuth.ts index 84c447e..c2245dd 100644 --- a/frontend/src/lib/services/UnityAuth/UnityAuth.ts +++ b/frontend/src/lib/services/UnityAuth/UnityAuth.ts @@ -1,8 +1,14 @@ import type { AxiosInstance } from 'axios'; import { BaseObservable } from '../EventBus/EventBus'; -import type { CompleteLoginResponse, UnityAuthServiceProps } from './shared'; +import type { + CompleteLoginResponse, + GetTenantUsersResponse, + UnityAuthLoginResponse, + UnityAuthServiceProps +} from './shared'; import { CompleteLoginResponseSchema, + GetTenantUsersResponseSchema, UnityAuthLoginResponseSchema, UnityAuthServicePropsSchema } from './shared'; @@ -20,12 +26,15 @@ export type UnityAuthService = BaseObservable & { login(email: string, password: string): Promise; getLoginData(): CompleteLoginResponse | undefined; logout(): void; + getTenantUsers(id: number): Promise; + setAuthInfo(authInfo: UnityAuthLoginResponse | undefined): void; }; export class UnityAuthServiceImpl extends BaseObservable implements UnityAuthService { + private authTokenInterceptorId: number = -1; private loginDataKey: string = 'loginData'; private axiosInstance: AxiosInstance; private tenantsResolver: TenantsResolver; @@ -91,6 +100,22 @@ export class UnityAuthServiceImpl return CompleteLoginResponseSchema.parse(JSON.parse(loginInfo)); } } + + async getTenantUsers(id: number): Promise { + const res = await this.axiosInstance.get(`/api/tenants/${id}/users`); + return GetTenantUsersResponseSchema.parse(res.data); + } + + setAuthInfo(authInfo: UnityAuthLoginResponse | undefined): void { + if (authInfo) { + this.authTokenInterceptorId = this.axiosInstance.interceptors.request.use(function (config) { + config.headers['Authorization'] = `Bearer ${authInfo.access_token}`; + return config; + }); + } else { + this.axiosInstance.interceptors.request.eject(this.authTokenInterceptorId); + } + } } export function unityAuthServiceFactory(props: UnityAuthServiceProps): UnityAuthService { diff --git a/frontend/src/lib/services/UnityAuth/shared.ts b/frontend/src/lib/services/UnityAuth/shared.ts index 3e5e9b3..d45d2b7 100644 --- a/frontend/src/lib/services/UnityAuth/shared.ts +++ b/frontend/src/lib/services/UnityAuth/shared.ts @@ -1,6 +1,7 @@ import { z } from 'zod'; import type { TenantsResolver } from '../TenantsResolver/TenantsResolver'; -import { TenantsSchema } from '../TenantsResolver/shared'; +import { TenantSchema } from '../TenantsResolver/shared'; +import { TenantUserSchema } from '$lib/context/TenantUsersContext/TenantUsers'; export const UnityAuthServicePropsSchema = z.object({ baseURL: z.string() @@ -15,7 +16,7 @@ export const UnityAuthLoginResponseSchema = z.object({ token_type: z.string(), expires_in: z.number(), username: z.string(), - tenants: z.array(TenantsSchema).optional() + tenants: z.array(TenantSchema).optional() }); export type UnityAuthLoginResponse = z.infer; @@ -23,3 +24,10 @@ export type UnityAuthLoginResponse = z.infer; + +export const GetTenantUsersResponseSchema = z.array(TenantUserSchema); +export type GetTenantUsersResponse = z.infer; + +export type TenantUsersResponse = { + tenantUsers: GetTenantUsersResponse; +}; diff --git a/frontend/src/lib/utils/types.ts b/frontend/src/lib/utils/types.ts new file mode 100644 index 0000000..0622161 --- /dev/null +++ b/frontend/src/lib/utils/types.ts @@ -0,0 +1,4 @@ +export type Maybe = T | undefined | null; +export type HasId = { + id: T; +}; diff --git a/frontend/src/routes/tenant/+layout.svelte b/frontend/src/routes/tenant/+layout.svelte index e203a32..58cba2f 100644 --- a/frontend/src/routes/tenant/+layout.svelte +++ b/frontend/src/routes/tenant/+layout.svelte @@ -1,13 +1,27 @@ - -
+ + +
diff --git a/frontend/src/routes/tenant/[tenant_id]/+page.svelte b/frontend/src/routes/tenant/[tenant_id]/+page.svelte new file mode 100644 index 0000000..97d2f52 --- /dev/null +++ b/frontend/src/routes/tenant/[tenant_id]/+page.svelte @@ -0,0 +1,33 @@ + + +
+ {#if tenantUsers} +
+ +
+ {/if} +
+ +