Sales import Working
This commit is contained in:
1 parent
7be26ad9da
commit
7656c7e877
11 files changed
+190
-77
No files matched your search
@@ -16,7 +16,7 @@
|
||||
<div class="two-col">
|
||||
<div class="col">
|
||||
<h3>Permissions</h3>
|
||||
@for (p of item().permissions; track p; let i = $index) {
|
||||
@for (p of item().permissions; track p.id; let i = $index) {
|
||||
<div class="row-container">
|
||||
<mat-checkbox
|
||||
[formField]="form.permissions[i].permission"
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<div class="col">
|
||||
<h3>Includes Roles</h3>
|
||||
@for (r of item().includedRoles; track r; let i = $index) {
|
||||
@for (r of item().includedRoles; track r.id; let i = $index) {
|
||||
<div class="row-container">
|
||||
<mat-checkbox [formField]="form.includedRoles[i].role" class="flex-auto">{{ r.name }}</mat-checkbox>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { Component, inject, afterNextRender, effect, input, computed, linkedSignal } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
computed,
|
||||
effect,
|
||||
inject,
|
||||
input,
|
||||
linkedSignal,
|
||||
untracked,
|
||||
afterNextRender,
|
||||
} from '@angular/core';
|
||||
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -12,14 +21,31 @@ import { Router } from '@angular/router';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
|
||||
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
|
||||
import { Role } from '../role';
|
||||
import { Permission } from '../permission';
|
||||
import { Role, RoleItem } from '../role';
|
||||
import { RoleService } from '../role.service';
|
||||
|
||||
export interface RoleDetailFormData {
|
||||
name: string;
|
||||
permissions: {
|
||||
id: string;
|
||||
name: string;
|
||||
permission: boolean;
|
||||
direct: boolean;
|
||||
disabled: boolean;
|
||||
}[];
|
||||
includedRoles: {
|
||||
id: string;
|
||||
name: string;
|
||||
role: boolean;
|
||||
permissionIds: string[];
|
||||
}[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-role-detail',
|
||||
templateUrl: './role-detail.component.html',
|
||||
styleUrls: ['./role-detail.component.css'],
|
||||
|
||||
imports: [
|
||||
FormField,
|
||||
FormRoot,
|
||||
@@ -44,63 +70,93 @@ export class RoleDetailComponent {
|
||||
|
||||
model = linkedSignal({
|
||||
source: this.item,
|
||||
computation: (itemVal) => ({
|
||||
name: itemVal.name ?? '',
|
||||
permissions: itemVal.permissions.map((x) => ({
|
||||
permission: x.enabled,
|
||||
disabled: false,
|
||||
})),
|
||||
includedRoles: itemVal.includedRoles.map((x) => ({
|
||||
role: x.enabled,
|
||||
})),
|
||||
}),
|
||||
computation: (itemVal): RoleDetailFormData => {
|
||||
const implied = new Set<string>();
|
||||
(itemVal.includedRoles || []).forEach((r) => {
|
||||
if (r.enabled) {
|
||||
(r.permissionIds || []).forEach((pid) => implied.add(pid));
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
name: itemVal.name ?? '',
|
||||
permissions: (itemVal.permissions || []).map((p) => {
|
||||
const isImplied = implied.has(p.id as string);
|
||||
const isDirect = p.enabled === true;
|
||||
return {
|
||||
id: p.id ?? '',
|
||||
name: p.name,
|
||||
permission: isImplied || isDirect,
|
||||
direct: isDirect,
|
||||
disabled: isImplied,
|
||||
};
|
||||
}),
|
||||
includedRoles: (itemVal.includedRoles || []).map((r) => ({
|
||||
id: r.id ?? '',
|
||||
name: r.name,
|
||||
role: r.enabled === true,
|
||||
permissionIds: r.permissionIds || [],
|
||||
})),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
form = createForm(this.model);
|
||||
|
||||
private enabledIncludedRoleIds = computed(() => {
|
||||
return this.model()
|
||||
.includedRoles.filter((r) => r.role)
|
||||
.map((r) => r.id)
|
||||
.sort()
|
||||
.join(',');
|
||||
});
|
||||
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form.name().focusBoundControl();
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
// Track changes to includedRoles explicitly
|
||||
this.model().includedRoles.map((x) => x.role);
|
||||
this.applyIncludedRolePermissionLocks();
|
||||
// Recompute permission locks whenever the set of enabled included roles changes
|
||||
this.enabledIncludedRoleIds();
|
||||
untracked(() => {
|
||||
this.applyIncludedRolePermissionLocks();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private applyIncludedRolePermissionLocks(): void {
|
||||
this.model.update((currentModel) => {
|
||||
const implied = new Set<string>();
|
||||
const currentItem = this.item();
|
||||
|
||||
currentItem.includedRoles.forEach((roleOpt, idx) => {
|
||||
const checked = currentModel.includedRoles[idx]?.role;
|
||||
if (checked) {
|
||||
(roleOpt.permissionIds || []).forEach((pid) => implied.add(pid));
|
||||
currentModel.includedRoles.forEach((role) => {
|
||||
if (role.role) {
|
||||
(role.permissionIds || []).forEach((pid) => implied.add(pid));
|
||||
}
|
||||
});
|
||||
|
||||
const newPerms = [...currentModel.permissions];
|
||||
let changed = false;
|
||||
const newPerms = currentModel.permissions.map((p) => {
|
||||
// If not disabled, direct state tracks the user's checkbox value
|
||||
const currentDirect = p.disabled ? p.direct : p.permission;
|
||||
const isImplied = implied.has(p.id);
|
||||
|
||||
currentItem.permissions.forEach((perm, idx) => {
|
||||
const isImplied = implied.has(perm.id as string);
|
||||
const isDirect = perm.enabled === true;
|
||||
const newPermission = isImplied ? true : currentDirect;
|
||||
const newDisabled = isImplied;
|
||||
|
||||
if (!newPerms[idx]) return;
|
||||
|
||||
if (isImplied) {
|
||||
if (!newPerms[idx].permission || !newPerms[idx].disabled) {
|
||||
newPerms[idx] = { permission: true, disabled: true };
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (newPerms[idx].permission !== isDirect || newPerms[idx].disabled) {
|
||||
newPerms[idx] = { permission: isDirect, disabled: false };
|
||||
changed = true;
|
||||
}
|
||||
if (
|
||||
p.direct !== currentDirect ||
|
||||
p.permission !== newPermission ||
|
||||
p.disabled !== newDisabled
|
||||
) {
|
||||
changed = true;
|
||||
return {
|
||||
...p,
|
||||
direct: currentDirect,
|
||||
permission: newPermission,
|
||||
disabled: newDisabled,
|
||||
};
|
||||
}
|
||||
return p;
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
@@ -149,21 +205,26 @@ export class RoleDetailComponent {
|
||||
|
||||
getItem(): Role {
|
||||
const formModel = this.model();
|
||||
const currentItem = this.item();
|
||||
currentItem.name = formModel.name ?? '';
|
||||
const permArray = formModel.permissions;
|
||||
|
||||
currentItem.permissions.forEach((p, index) => {
|
||||
if (permArray[index]?.disabled) {
|
||||
return;
|
||||
}
|
||||
p.enabled = permArray[index]?.permission ?? false;
|
||||
return new Role({
|
||||
...this.item(),
|
||||
name: formModel.name.trim(),
|
||||
permissions: formModel.permissions.map(
|
||||
(p) =>
|
||||
new Permission({
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
enabled: p.disabled ? p.direct : p.permission,
|
||||
}),
|
||||
),
|
||||
includedRoles: formModel.includedRoles.map(
|
||||
(r) =>
|
||||
new RoleItem({
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
enabled: r.role,
|
||||
permissionIds: r.permissionIds,
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
const includeArray = formModel.includedRoles;
|
||||
currentItem.includedRoles.forEach((r, index) => {
|
||||
r.enabled = includeArray[index]?.role ?? false;
|
||||
});
|
||||
return currentItem;
|
||||
}
|
||||
}
|
||||
@@ -164,6 +164,6 @@ export class SalesImportComponent {
|
||||
}
|
||||
|
||||
trackLine(_index: number, line: SaleLine): string {
|
||||
return `${line.skuId ?? line.productName}-${line.rate}-${line.isHappyHour}`;
|
||||
return `${line.skuId ?? line.name}-${line.rate}-${line.isHappyHour}`;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user