metis-desk/modules/companies/src/api/domain/work-profile.aggregate.ts
David b45925f3e2 feat(assets): implement asset picker dialog and selection components
- Added `useAssetPickerController` for managing asset selection logic.
- Created `AssetSelectProps` type for defining asset selection properties.
- Implemented `AssetPickerDialog` for displaying the asset selection interface.
- Developed `AssetPickerList` for rendering the list of selectable assets.
- Introduced `AssetSelect` component for integrating the asset picker into forms.
- Created `AssetList` component for shared asset listing functionality.
- Added tests for workstation creation logic to ensure proper validation.
- Implemented workstation asset fields and association fields for managing workstation assets.
- Developed workstation lifecycle dialog for managing work profile states.
- Added form progress component for visualizing multi-step forms.
2026-10-14 19:42:59 +02:00

107 lines
2.8 KiB
TypeScript

import type { UniqueID } from "@repo/rdx-ddd";
import { AggregateRoot } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils";
import { z } from "zod/v4";
import { WorkProfileValues } from "./value-objects/work-profile-values.vo";
import { WorkProfileRevision } from "./work-profile-revision.entity";
import { WorkProfileError } from "./work-profile-values";
type WorkProfileProps = Readonly<{
companyId: UniqueID;
values: WorkProfileValues;
history: readonly WorkProfileRevision[];
}>;
export class WorkProfile extends AggregateRoot<WorkProfileProps> {
private constructor(props: WorkProfileProps, id?: UniqueID) {
super(Object.freeze({ ...props, history: Object.freeze([...props.history]) }), id);
}
static create(
companyId: UniqueID,
values: WorkProfileValues,
actorId: UniqueID,
recordedAt: string
): Result<WorkProfile, WorkProfileError> {
if (!z.iso.datetime().safeParse(recordedAt).success) {
return Result.fail(new WorkProfileError("INVALID_REQUEST"));
}
return Result.ok(
new WorkProfile({
companyId,
values,
history: [WorkProfileRevision.create({ values, actorId, recordedAt })],
})
);
}
static rehydrate(props: WorkProfileProps, id: UniqueID) {
return new WorkProfile(props, id);
}
get companyId() {
return this.props.companyId;
}
get values() {
return this.props.values;
}
get history() {
return this.props.history;
}
deactivate(actorId: UniqueID, recordedAt: string): Result<WorkProfile, WorkProfileError> {
const values = WorkProfileValues.create({ ...this.values.toPrimitive(), active: false });
return values.isSuccess ? this.update(values.data, actorId, recordedAt) : values;
}
checkRemoval({
hasConfigurations,
}: {
hasConfigurations: boolean;
}): Result<void, WorkProfileError> {
if (this.values.active) {
return Result.fail(new WorkProfileError("PROFILE_ACTIVE"));
}
if (hasConfigurations) {
return Result.fail(new WorkProfileError("PROFILE_IN_USE"));
}
return Result.ok(undefined);
}
update(
values: WorkProfileValues,
actorId: UniqueID,
recordedAt: string
): Result<WorkProfile, WorkProfileError> {
if (this.values.equals(values)) {
return Result.ok(this);
}
if (!this.values.sameTarget(values)) {
return Result.fail(new WorkProfileError("PROFILE_TARGET_IMMUTABLE"));
}
if (
!z.iso.datetime().safeParse(recordedAt).success ||
recordedAt < (this.history.at(-1)?.recordedAt ?? "")
) {
return Result.fail(new WorkProfileError("INVALID_REQUEST"));
}
return Result.ok(
new WorkProfile(
{
...this.props,
values,
history: [...this.history, WorkProfileRevision.create({ values, actorId, recordedAt })],
},
this.id
)
);
}
}