feat: implement dynamic form and popup components

- Added DynamicField interface to define form field structure.
- Created DynamicFormConfig interface for form configuration.
- Developed DynamicFormComponent to handle dynamic form rendering and validation.
- Implemented DynamicPopupComponent for displaying forms in a modal dialog.
- Added HTML and SCSS for dynamic form and popup styling.
- Integrated Material Design components for form inputs and buttons.
- Implemented form submission logic with API integration.
- Added tests for DynamicForm and DynamicPopup components.
- Updated global styles for Material components in themed popups.
- Included Material Icons in index.html for better UI representation.
This commit is contained in:
2026-02-15 03:56:17 +05:30
parent 9e34de73ee
commit 55b436c7d2
43 changed files with 2043 additions and 186 deletions
+2 -2
View File
@@ -12,7 +12,7 @@
<button [ngClass]="{active: filter === 'All'}" (click)="filterProjects('All')">All</button>
</li>
@for (category of model.projectsCategories; track category) {
@for (category of projectsCategories; track category) {
<li class="filter-item">
<button (click)="filterProjects(category)"
[ngClass]="{active: filter === category}">{{category}}</button>
@@ -40,7 +40,7 @@
<button (click)="filterProjects('All')">All</button>
</li>
@for (category of model.projectsCategories; track category) {
@for (category of projectsCategories; track category) {
<li class="select-item">
<button (click)="filterProjects(category)">{{category}}</button>
</li>
+41 -26
View File
@@ -1,10 +1,10 @@
import { Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit } from '@angular/core';
import { Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit, OnDestroy } from '@angular/core';
import { IProject } from '../models/project.model';
import { BaseComponent } from '../base.component';
import { AdminService } from '../services/admin.service';
import { IProjects } from './projects.model';
import { Subscription } from 'rxjs';
import { CommonModule } from '@angular/common';
import { AdminQuery } from '../state/admin.query';
import { AdminStateService } from '../state/admin-state.service';
import { Subject, takeUntil } from 'rxjs';
import { environment } from '../../../environments/environment';
@Component({
selector: 'app-projects',
@@ -13,35 +13,50 @@ import { CommonModule } from '@angular/common';
imports: [CommonModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class Projects extends BaseComponent<IProjects> implements OnInit {
export class Projects implements OnInit, OnDestroy {
filter = 'All';
projects!: IProject[];
subscription: Subscription = {} as Subscription;
projects: IProject[] = [];
projectsCategories: string[] = [];
categoryClicked = false;
constructor() {
const svc = inject(AdminService);
super(svc);
}
imagesOrigin = environment.apiUrl + '/images/';
private adminQuery = inject(AdminQuery);
private adminState = inject(AdminStateService);
private destroy$ = new Subject<void>();
projects$ = this.adminQuery.projects$;
loading$ = this.adminQuery.projectsLoading$;
ngOnInit(): void {
this.getProjects();
}
const candidateId = this.adminQuery.getCandidateId();
this.adminState.loadProjects(candidateId)
.pipe(takeUntil(this.destroy$))
.subscribe();
getProjects() {
this.svc.getProjects(this.candidateId).subscribe((response: IProjects) => {
this.svc.projects = this.svc.projects ?? response;
this.projects = response.projects;
this.assignData(response);
});
this.projects$
.pipe(takeUntil(this.destroy$))
.subscribe(data => {
if (data) {
this.projects = data.projects;
this.projectsCategories = data.projectsCategories;
}
});
}
filterProjects(category: string) {
this.filter = category;
this.projects = this.filter === 'All'
? this.model.projects
: this.model.projects.filter(
(project: IProject) => {
return project.categories.includes(category)
});
const allProjects = this.adminQuery.getProjects();
if (!allProjects) return;
this.projects = category === 'All'
? allProjects.projects
: allProjects.projects.filter(
(project: IProject) => project.categories.includes(category)
);
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}