feat: add Angular member and user models + API services
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
|||||||
|
export type MemberStatus = 'Member' | 'Visitor' | 'Inactive' | 'Former';
|
||||||
|
|
||||||
|
export interface MemberListItemDto {
|
||||||
|
id: number;
|
||||||
|
firstName_en: string;
|
||||||
|
lastName_en: string;
|
||||||
|
nickName: string | null;
|
||||||
|
firstName_zh: string | null;
|
||||||
|
lastName_zh: string | null;
|
||||||
|
status: MemberStatus;
|
||||||
|
email: string | null;
|
||||||
|
phoneCell: string | null;
|
||||||
|
joinDate: string | null;
|
||||||
|
linkedUserId: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemberDto extends MemberListItemDto {
|
||||||
|
gender: string | null;
|
||||||
|
dateOfBirth: string | null;
|
||||||
|
baptismDate: string | null;
|
||||||
|
baptismChurch: string | null;
|
||||||
|
phoneHome: string | null;
|
||||||
|
address: string | null;
|
||||||
|
city: string | null;
|
||||||
|
state: string | null;
|
||||||
|
zipCode: string | null;
|
||||||
|
country: string;
|
||||||
|
photoBlobPath: string | null;
|
||||||
|
languagePreference: string;
|
||||||
|
notes: string | null;
|
||||||
|
familyUnitId: number | null;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateMemberRequest {
|
||||||
|
firstName_en: string;
|
||||||
|
lastName_en: string;
|
||||||
|
nickName: string | null;
|
||||||
|
firstName_zh: string | null;
|
||||||
|
lastName_zh: string | null;
|
||||||
|
gender: string | null;
|
||||||
|
dateOfBirth: string | null;
|
||||||
|
baptismDate: string | null;
|
||||||
|
baptismChurch: string | null;
|
||||||
|
email: string | null;
|
||||||
|
phoneCell: string | null;
|
||||||
|
phoneHome: string | null;
|
||||||
|
address: string | null;
|
||||||
|
city: string | null;
|
||||||
|
state: string | null;
|
||||||
|
zipCode: string | null;
|
||||||
|
country: string;
|
||||||
|
status: string;
|
||||||
|
languagePreference: string;
|
||||||
|
joinDate: string | null;
|
||||||
|
notes: string | null;
|
||||||
|
familyUnitId: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateMemberRequest = CreateMemberRequest;
|
||||||
|
|
||||||
|
export interface PagedResult<T> {
|
||||||
|
items: T[];
|
||||||
|
totalCount: number;
|
||||||
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemberQueryParams {
|
||||||
|
page?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
search?: string;
|
||||||
|
status?: string;
|
||||||
|
hasUser?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Display name: NickName (if present) else FirstName_en, plus LastName_en */
|
||||||
|
export function memberDisplayName(
|
||||||
|
m: Pick<MemberListItemDto, 'nickName' | 'firstName_en' | 'lastName_en'>
|
||||||
|
): string {
|
||||||
|
return `${m.nickName ?? m.firstName_en} ${m.lastName_en}`;
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { ApiConfigService } from '../../../core/services/api-config.service';
|
||||||
|
import {
|
||||||
|
MemberDto, MemberListItemDto, CreateMemberRequest,
|
||||||
|
UpdateMemberRequest, MemberQueryParams, PagedResult
|
||||||
|
} from '../models/member.model';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class MemberApiService {
|
||||||
|
private readonly endpoint: string;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient, apiConfig: ApiConfigService) {
|
||||||
|
this.endpoint = apiConfig.getApiUrl('members');
|
||||||
|
}
|
||||||
|
|
||||||
|
getPaged(params: MemberQueryParams = {}): Observable<PagedResult<MemberListItemDto>> {
|
||||||
|
let p = new HttpParams()
|
||||||
|
.set('page', params.page ?? 1)
|
||||||
|
.set('pageSize', params.pageSize ?? 20);
|
||||||
|
if (params.search !== undefined && params.search !== '') p = p.set('search', params.search);
|
||||||
|
if (params.status !== undefined && params.status !== '') p = p.set('status', params.status);
|
||||||
|
if (params.hasUser !== undefined) p = p.set('hasUser', params.hasUser);
|
||||||
|
return this.http.get<PagedResult<MemberListItemDto>>(this.endpoint, { params: p });
|
||||||
|
}
|
||||||
|
|
||||||
|
getById(id: number): Observable<MemberDto> {
|
||||||
|
return this.http.get<MemberDto>(`${this.endpoint}/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
create(request: CreateMemberRequest): Observable<{ id: number }> {
|
||||||
|
return this.http.post<{ id: number }>(this.endpoint, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(id: number, request: UpdateMemberRequest): Observable<void> {
|
||||||
|
return this.http.put<void>(`${this.endpoint}/${id}`, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(id: number): Observable<void> {
|
||||||
|
return this.http.delete<void>(`${this.endpoint}/${id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
export interface UserListItemDto {
|
||||||
|
id: string;
|
||||||
|
email: string;
|
||||||
|
memberId: number | null;
|
||||||
|
memberDisplayName: string | null;
|
||||||
|
roles: string[];
|
||||||
|
isActive: boolean;
|
||||||
|
languagePreference: string;
|
||||||
|
lastLoginAt: string | null;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserDto = UserListItemDto;
|
||||||
|
|
||||||
|
export interface CreateUserRequest {
|
||||||
|
memberId: number;
|
||||||
|
email: string;
|
||||||
|
roles: string[];
|
||||||
|
languagePreference: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateUserResult {
|
||||||
|
userId: string;
|
||||||
|
tempPassword: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateUserRequest {
|
||||||
|
email: string;
|
||||||
|
roles: string[];
|
||||||
|
isActive: boolean;
|
||||||
|
languagePreference: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserQueryParams {
|
||||||
|
page?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
search?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PagedResult<T> {
|
||||||
|
items: T[];
|
||||||
|
totalCount: number;
|
||||||
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ALL_ROLES = [
|
||||||
|
'super_admin','pastor','board_member','coworker_chair','ministry_leader',
|
||||||
|
'district_leader','cell_leader','coworker','finance','secretary',
|
||||||
|
'worship_leader','member','visitor'
|
||||||
|
] as const;
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { ApiConfigService } from '../../../core/services/api-config.service';
|
||||||
|
import {
|
||||||
|
UserDto, UserListItemDto, CreateUserRequest, CreateUserResult,
|
||||||
|
UpdateUserRequest, UserQueryParams, PagedResult
|
||||||
|
} from '../models/user.model';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class UserApiService {
|
||||||
|
private readonly endpoint: string;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient, apiConfig: ApiConfigService) {
|
||||||
|
this.endpoint = apiConfig.getApiUrl('users');
|
||||||
|
}
|
||||||
|
|
||||||
|
getPaged(params: UserQueryParams = {}): Observable<PagedResult<UserListItemDto>> {
|
||||||
|
let p = new HttpParams()
|
||||||
|
.set('page', params.page ?? 1)
|
||||||
|
.set('pageSize', params.pageSize ?? 20);
|
||||||
|
if (params.search) p = p.set('search', params.search);
|
||||||
|
return this.http.get<PagedResult<UserListItemDto>>(this.endpoint, { params: p });
|
||||||
|
}
|
||||||
|
|
||||||
|
getById(id: string): Observable<UserDto> {
|
||||||
|
return this.http.get<UserDto>(`${this.endpoint}/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
createUser(request: CreateUserRequest): Observable<CreateUserResult> {
|
||||||
|
return this.http.post<CreateUserResult>(this.endpoint, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(id: string, request: UpdateUserRequest): Observable<void> {
|
||||||
|
return this.http.put<void>(`${this.endpoint}/${id}`, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
deactivate(id: string): Observable<void> {
|
||||||
|
return this.http.delete<void>(`${this.endpoint}/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPassword(id: string): Observable<{ tempPassword: string }> {
|
||||||
|
return this.http.post<{ tempPassword: string }>(
|
||||||
|
`${this.endpoint}/${id}/reset-password`, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user