172 lines
5.1 KiB
TypeScript
172 lines
5.1 KiB
TypeScript
import type { GymPlan } from "@/lib/models/gym-plan"
|
|
import type { PaymentStatus, SubscriptionSummary } from "@/lib/models/subscription"
|
|
|
|
/** One weekly weigh-in (CusWeightLossProgress). */
|
|
export interface WeightProgressPoint {
|
|
weeklyProgressId: string
|
|
weight?: number | null
|
|
recordedAt: string
|
|
}
|
|
|
|
/** A member's goal/measurements (CustomerTarget) with their weight history. */
|
|
export interface CustomerTarget {
|
|
customerTargetId: string
|
|
currentWeight?: number | null
|
|
currentHeight?: number | null
|
|
targetWeight?: number | null
|
|
goal?: string | null
|
|
timePeriod?: string | null
|
|
weeklyProgresses?: WeightProgressPoint[] | null
|
|
}
|
|
|
|
/** Customer entity as serialized by the backend (camelCase of the EF model). */
|
|
export interface MemberProfile {
|
|
cusId: string
|
|
cusName?: string | null
|
|
gender?: string | null
|
|
/** Date of birth, "yyyy-MM-dd". Backend property is BoD. */
|
|
boD?: string | null
|
|
primaryPH?: string | null
|
|
secondaryPH?: string | null
|
|
email?: string | null
|
|
nic?: string | null
|
|
address?: string | null
|
|
fkUserId?: string
|
|
isActive: boolean
|
|
createdAt: string
|
|
isLocked?: boolean
|
|
lockReason?: string | null
|
|
lockedAt?: string | null
|
|
customerTargets?: CustomerTarget[] | null
|
|
user?: {
|
|
userId: string
|
|
userName?: string | null
|
|
email?: string | null
|
|
phoneNumber?: string | null
|
|
} | null
|
|
}
|
|
|
|
/** A workout/meal plan the member is assigned to. */
|
|
export interface FollowedPlan {
|
|
planId: string
|
|
name?: string | null
|
|
isFollowing: boolean
|
|
completedDate?: string | null
|
|
}
|
|
|
|
/** GET client/customers/{id}/full — the "More Info" aggregate. */
|
|
export interface MemberFullDetail {
|
|
customer: MemberProfile
|
|
subscriptions?: SubscriptionSummary[]
|
|
workoutPlans: FollowedPlan[]
|
|
mealPlans: FollowedPlan[]
|
|
}
|
|
|
|
/** POST client/customers/{id}/medical (password-gated). */
|
|
export interface MedicalDetails {
|
|
bloodGroup?: string | null
|
|
disabilities?: string | null
|
|
}
|
|
|
|
/**
|
|
* Row shape of GET client/customers (MemberListRowDto): one row per member.
|
|
* Group members each get a row pointing at their shared subscription.
|
|
*/
|
|
export interface MemberSubscription {
|
|
subscriptionId: string
|
|
fkCustomerPlanId: string
|
|
fkCustomerId: string
|
|
onboardDate: string
|
|
/** Frozen at creation, never changes again -- use renewalDate for current status/listing. */
|
|
expiryDate?: string | null
|
|
renewalDate?: string | null
|
|
isActive: boolean
|
|
createdAt: string
|
|
customer?: MemberProfile | null
|
|
isPrimary: boolean
|
|
/** False when unassigned from the plan but still a member of the gym — re-assignable. */
|
|
isPlanAssigned?: boolean
|
|
planName?: string | null
|
|
/** "None" means this member was created without a plan yet — assign one to make them active. */
|
|
planScope?: "Individual" | "Group" | "None"
|
|
memberCount?: number
|
|
memberLimit?: number
|
|
invoiceAmount?: number
|
|
paidAmount?: number
|
|
balance?: number
|
|
paymentStatus?: PaymentStatus
|
|
allowSplitPayments?: boolean
|
|
fingerprintId?: number | null
|
|
fingerprintName?: string | null
|
|
accessProfileId?: number | null
|
|
accessNumber?: string | null
|
|
accessProvisionStatus?: "NotConfigured" | "NoDevice" | "Pending" | "Synced" | "Failed"
|
|
actualAccessState?: "Unknown" | "Enabled" | "Disabled" | "Mixed"
|
|
desiredAccessState?: "Enabled" | "Disabled"
|
|
fingerprintCount?: number
|
|
accessLastError?: string | null
|
|
isLocked?: boolean
|
|
lockReason?: string | null
|
|
/** Face-photo enrolment on the gym's access terminals. */
|
|
hasFacePhoto?: boolean
|
|
facePhotoStatus?: "None" | "Pending" | "Synced" | "Failed"
|
|
facePhotoError?: string | null
|
|
}
|
|
|
|
/** GET client/customers/unlinked-fingerprints — a device enrollment not yet linked to a Customer. */
|
|
export interface UnlinkedFingerprint {
|
|
id: string
|
|
deviceUserId: number
|
|
deviceEmployeeNo: string
|
|
deviceReportedName?: string | null
|
|
deviceUserType?: string | null
|
|
fingerprintCount: number
|
|
deviceId: string
|
|
deviceName?: string | null
|
|
discoveredAt: string
|
|
}
|
|
|
|
export interface AccessCommandStatus {
|
|
accessProfileId: number
|
|
accessNumber: string
|
|
personType: "Customer" | "Staff"
|
|
desiredAccessState: "Enabled" | "Disabled"
|
|
provisionStatus: "NoDevice" | "Pending" | "Synced" | "Failed"
|
|
actualAccessState: "Unknown" | "Enabled" | "Disabled" | "Mixed"
|
|
fingerprintCount: number
|
|
lastError?: string | null
|
|
lastSyncedAt?: string | null
|
|
deviceCount: number
|
|
syncedDeviceCount: number
|
|
}
|
|
|
|
/** GET client/customers/{id} response. */
|
|
export interface MemberDetail {
|
|
customer: MemberProfile
|
|
plans: GymPlan[]
|
|
subscriptions?: SubscriptionSummary[]
|
|
}
|
|
|
|
export interface MemberInput {
|
|
fullname: string
|
|
userName: string
|
|
email: string
|
|
mobileNumber: string
|
|
gender: string
|
|
/** "yyyy-MM-dd" */
|
|
birthday: string
|
|
nic?: string
|
|
customerPlanId?: string
|
|
workoutPlanIds?: string[]
|
|
mealPlanIds?: string[]
|
|
/** ISO datetime. Only meaningful alongside customerPlanId. */
|
|
onboardDate?: string
|
|
/** false bills the plan at Rs. 0.00 and skips the automatic payment link. */
|
|
chargePayment?: boolean
|
|
discountType?: "Percentage" | "Flat"
|
|
discountValue?: number
|
|
/** Set true only on the resubmit after staff has confirmed linking an existing platform
|
|
* customer to this gym (see CreateMemberResult.requiresConfirmation). */
|
|
confirmLink?: boolean
|
|
}
|