diff --git a/client/src/app/app.component.css b/client/src/app/app.component.css index e69de29..d2daae3 100644 --- a/client/src/app/app.component.css +++ b/client/src/app/app.component.css @@ -0,0 +1,14 @@ +.main{ + align-items: center; + padding: 15px; + display: flex; + justify-content: center; + margin-bottom: 40px; + margin-top: 20px; +} +.main button{ + padding: 10px; + font-size: 16px; + font-weight: 600; + border-radius: 10px; +} \ No newline at end of file diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index bf8f0fb..63bf361 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -1 +1,4 @@ -

das

\ No newline at end of file +
+ +
+ diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 87aaf53..42d9a33 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -1,4 +1,6 @@ import { Component } from '@angular/core'; +import { UserModel } from './user.model'; +import { UserService } from './user.service'; @Component({ selector: 'app-root', @@ -6,5 +8,19 @@ import { Component } from '@angular/core'; styleUrls: ['./app.component.css'] }) export class AppComponent { - title = 'client'; + userData: UserModel[] = []; + loadButton="Load Data"; + showTable = false; + + constructor(private userService: UserService) { } + + onLoadData(){ + this.loadButton = "Refresh data"; + this.showTable = true; + this.userService.getUsers().subscribe( + responseData=>{ + this.userData = responseData; + } + ) + } } diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 8dfc1d6..a95b8ac 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -1,14 +1,24 @@ +import { HttpClientModule } from '@angular/common/http'; import { NgModule } from '@angular/core'; +import { ReactiveFormsModule} from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; +import { TabularComponent } from './tabular/tabular.component'; +import { UserAddComponent } from './tabular/user-add/user-add.component'; +import { DateformatPipe } from './tabular/dateformat.pipe'; @NgModule({ declarations: [ - AppComponent + AppComponent, + TabularComponent, + UserAddComponent, + DateformatPipe ], imports: [ - BrowserModule + BrowserModule, + ReactiveFormsModule, + HttpClientModule ], providers: [], bootstrap: [AppComponent] diff --git a/client/src/app/tabular/dateformat.pipe.spec.ts b/client/src/app/tabular/dateformat.pipe.spec.ts new file mode 100644 index 0000000..6cbc4e0 --- /dev/null +++ b/client/src/app/tabular/dateformat.pipe.spec.ts @@ -0,0 +1,8 @@ +import { DateformatPipe } from './dateformat.pipe'; + +describe('DateformatPipe', () => { + it('create an instance', () => { + const pipe = new DateformatPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/client/src/app/tabular/dateformat.pipe.ts b/client/src/app/tabular/dateformat.pipe.ts new file mode 100644 index 0000000..a44aa29 --- /dev/null +++ b/client/src/app/tabular/dateformat.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'dateformat' +}) +export class DateformatPipe implements PipeTransform { + + transform(value: string): string { + const date = new Date(value); + return date.getDate()+" "+date.toLocaleString('en-US', {month: 'long',})+" "+date.getFullYear()+" Time: "+date.getHours()+":"+date.getMinutes(); + } + +} diff --git a/client/src/app/tabular/tabular.component.css b/client/src/app/tabular/tabular.component.css new file mode 100644 index 0000000..b7e0ce2 --- /dev/null +++ b/client/src/app/tabular/tabular.component.css @@ -0,0 +1,43 @@ +.table_tag{ + display:revert; + width: 100%; + border: 2px solid; + border-radius: 10px; + border-color: darkgray; + padding: 5px; + padding-top: 10px; + padding-bottom: 10px; + box-shadow: 2px 5px 2px gainsboro; + border-collapse: separate; + border-spacing: 0 1em; +} +.table_tag tr{ + border-bottom: 2px solid; +} +.table_tag th{ + font-size: 20px; + padding: 10px; + text-align: center; +} +.table_tag td{ + text-align: center; + font-size: 1em; + /* box-sizing: border-box; */ + +} +td input{ + height: 30px; + font-size: 1em; + background-color: white; + +} +.btn{ + margin-right: 10px; + background-color: dodgerblue !important; + color: white; + border-radius: 12px; +} +.btn-danger{ + background-color: coral !important; + border-radius: 12px; +} \ No newline at end of file diff --git a/client/src/app/tabular/tabular.component.html b/client/src/app/tabular/tabular.component.html new file mode 100644 index 0000000..d44904b --- /dev/null +++ b/client/src/app/tabular/tabular.component.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + +
{{head}}
+ + +
\ No newline at end of file diff --git a/client/src/app/tabular/tabular.component.spec.ts b/client/src/app/tabular/tabular.component.spec.ts new file mode 100644 index 0000000..464c594 --- /dev/null +++ b/client/src/app/tabular/tabular.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TabularComponent } from './tabular.component'; + +describe('TabularComponent', () => { + let component: TabularComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ TabularComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TabularComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/tabular/tabular.component.ts b/client/src/app/tabular/tabular.component.ts new file mode 100644 index 0000000..81b5e99 --- /dev/null +++ b/client/src/app/tabular/tabular.component.ts @@ -0,0 +1,77 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { UserModel, columnName} from '../user.model'; +import { UserService } from '../user.service'; + +@Component({ + selector: 'app-tabular', + templateUrl: './tabular.component.html', + styleUrls: ['./tabular.component.css'] +}) +export class TabularComponent implements OnInit { + prevArray:string[] = []; + @Input ('userdata') userData:UserModel[]; + saveEnable = false; + header = Object.values(columnName); + + constructor(private userService: UserService) { } + + ngOnInit(): void { + } + + onUpdatedData(){ + this.userService.getUsers().subscribe(newData=>{ + this.userData = newData; + }); + } + + onEdit(event:any){ + event.path[0].value = "Save"; + event.path[1].childNodes[1].value = "Cancel"; + for(let j=0;j{ + this.userService.getUsers().subscribe(newData=>{ + this.userData = newData; + }); + }); + + } + + onCancel(event:any){ + this.saveEnable = false; + event.path[0].value = "Delete"; + event.path[1].childNodes[0].value = "Edit"; + let j:number=0; + for(j=0;j{ + this.userService.getUsers().subscribe(newData=>{ + this.userData = newData; + }); + }) + } + + +} diff --git a/client/src/app/tabular/user-add/user-add.component.css b/client/src/app/tabular/user-add/user-add.component.css new file mode 100644 index 0000000..b9a0db9 --- /dev/null +++ b/client/src/app/tabular/user-add/user-add.component.css @@ -0,0 +1,25 @@ +.input_tag{ + display: flex; + justify-content: space-around; + text-align: center; + font-size: 1em; + margin-bottom: 10px; +} +.input_tag input{ + height: 30px; + font-size: 1em; + background-color: white; + border-color: #cbb3b3; + border-radius: 10px; +} +.btn{ + padding: 10px; + padding-bottom: 25px; + background-color: dodgerblue !important; + color:white +} +.input_tag p{ + margin-block-start:5px; + margin-block-end: 5px; + color: red; +} \ No newline at end of file diff --git a/client/src/app/tabular/user-add/user-add.component.html b/client/src/app/tabular/user-add/user-add.component.html new file mode 100644 index 0000000..ca208ed --- /dev/null +++ b/client/src/app/tabular/user-add/user-add.component.html @@ -0,0 +1,37 @@ +
+
+ +

This field is required!

+
+
+ +
+
+ +

This field is required!

+
+
+ +

Please enter a valid email!

+
+
+ +

This field is required!

+
+
+ +
+

Please choose from given role:

+

SuperAdmin , Admin , Subscriber

+
+
+
+ +

This field is required!

+
+
+ +

Please Enter the valid data!

+
+
+ diff --git a/client/src/app/tabular/user-add/user-add.component.spec.ts b/client/src/app/tabular/user-add/user-add.component.spec.ts new file mode 100644 index 0000000..7792570 --- /dev/null +++ b/client/src/app/tabular/user-add/user-add.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserAddComponent } from './user-add.component'; + +describe('UserAddComponent', () => { + let component: UserAddComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ UserAddComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UserAddComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/tabular/user-add/user-add.component.ts b/client/src/app/tabular/user-add/user-add.component.ts new file mode 100644 index 0000000..0d749a5 --- /dev/null +++ b/client/src/app/tabular/user-add/user-add.component.ts @@ -0,0 +1,65 @@ +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; +import { UserService } from 'src/app/user.service'; +import { Role } from '../../user.model'; + +@Component({ + selector: 'app-user-add', + templateUrl: './user-add.component.html', + styleUrls: ['./user-add.component.css'], +}) +export class UserAddComponent implements OnInit { + @Output() updatedData = new EventEmitter(); + addUserForm: FormGroup; + addButtonClicked = false; + role = Role; + + constructor(private userService: UserService) {} + + ngOnInit(): void { + this.addUserForm = new FormGroup({ + firstName: new FormControl(null, [Validators.required]), + middleName: new FormControl(null), + lastName: new FormControl(null, [Validators.required]), + email: new FormControl(null, [Validators.required, Validators.email]), + phoneNumber: new FormControl(null, [Validators.required]), + role: new FormControl(null, [ + Validators.required, + this.forbiddenNames.bind(this), + ]), + address: new FormControl(null, [Validators.required]), + createdDate: new FormControl(null), + }); + } + + onSubmit() { + console.log(this.addUserForm); + if (this.addUserForm.status === 'INVALID') { + this.addButtonClicked = true; + return; + } + // else if(this.addUserForm.get('role')){ + + // } + else { + this.addButtonClicked = false; + this.addUserForm.patchValue({ + createdDate: new Date(), + }); + this.userService + .addUser(this.addUserForm.value) + .subscribe((responseData) => { + this.addUserForm.reset(); + this.updatedData.emit(); + }); + } + } + + forbiddenNames(control: FormControl): { [s: string]: boolean } | null { + if (control.value in this.role) { + return null; + } else { + return { roleIsForbidden: true }; + } + } +} diff --git a/client/src/app/user.model.ts b/client/src/app/user.model.ts new file mode 100644 index 0000000..233333b --- /dev/null +++ b/client/src/app/user.model.ts @@ -0,0 +1,29 @@ +export interface UserModel{ + userId?: string, + firstName: string, + middleName: string, + lastName: string, + email: string, + phoneNumber: number, + role: string, + address: string, + createdDate: string, +} + +export enum Role { + superAdmin = "SuperAdmin", + Admin = "Admin", + Subscriber = "Subscriber" +} + +export enum columnName{ + firstName = 'First Name', + middleName = 'Middle Name', + lastName= 'Last Name', + email= 'Email', + phoneNumber = 'Phone Number', + role= 'Role', + address = 'Address', + createdDate = 'User Created Date', + edit = 'Edit' + } \ No newline at end of file diff --git a/client/src/app/user.service.spec.ts b/client/src/app/user.service.spec.ts new file mode 100644 index 0000000..3f804c9 --- /dev/null +++ b/client/src/app/user.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UserService } from './user.service'; + +describe('UserService', () => { + let service: UserService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UserService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/client/src/app/user.service.ts b/client/src/app/user.service.ts new file mode 100644 index 0000000..251bd4b --- /dev/null +++ b/client/src/app/user.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {UserModel} from './user.model'; +import { map } from 'rxjs'; +import {environment} from '../environments/environment'; + +@Injectable({ + providedIn: 'root' +}) +export class UserService { + + constructor(private http: HttpClient) { } + + getUsers(){ + return this.http.get<{[key: string]:UserModel}>(environment.apiURL).pipe( + map((responseData)=>{ + const userArray:UserModel[] = []; + for (const key in responseData){ + if(responseData.hasOwnProperty(key)){ + userArray.push({...responseData[key]}); + } + } + return userArray; + }) + ) + } + + deleteUser(id:string){ + return this.http.delete(`${environment.apiURL}/${id}`); + } + + addUser(userData:UserModel){ + return this.http.post(environment.apiURL,userData); + } + + editUser(id:string,userData:{[key: string]: string}){ + console.log(userData); + return this.http.put(`${environment.apiURL}/${id}`,userData); + } +} diff --git a/client/src/environments/environment.ts b/client/src/environments/environment.ts index f56ff47..10e01a9 100644 --- a/client/src/environments/environment.ts +++ b/client/src/environments/environment.ts @@ -3,7 +3,8 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false, + apiURL: 'http://localhost:9010/users' }; /* diff --git a/client/src/styles.css b/client/src/styles.css index 90d4ee0..4bf22ac 100644 --- a/client/src/styles.css +++ b/client/src/styles.css @@ -1 +1,4 @@ /* You can add global styles to this file, and also import other style files */ +body{ + font-family: sans-serif; +} \ No newline at end of file diff --git a/client/tsconfig.json b/client/tsconfig.json index ff06eae..d01d793 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -21,7 +21,8 @@ "lib": [ "es2020", "dom" - ] + ], + "strictPropertyInitialization":false }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, diff --git a/server/package-lock.json b/server/package-lock.json index cc1e58c..5aa1f07 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "server", "version": "1.0.0", "license": "ISC", "dependencies": { diff --git a/server/src/controller/user.ts b/server/src/controller/user.ts index 62782fc..ba15ec6 100644 --- a/server/src/controller/user.ts +++ b/server/src/controller/user.ts @@ -14,7 +14,7 @@ export const getUserData = (req:any,res:any)=>{ export const deleteUser = (req:any,res:any)=>{ const {id} = req.params - pool.query('DELETE FROM users WHERE user_id = $1',[id],(q_err:any,q_res:any)=>{ + pool.query('DELETE FROM users WHERE userId = $1',[id],(q_err:any,q_res:any)=>{ if(q_err){ console.log(q_err); res.code = 404 @@ -25,7 +25,7 @@ export const deleteUser = (req:any,res:any)=>{ } export const createUser = (req:any,res:any)=>{ const data = [req.body.firstName,req.body.middleName,req.body.lastName,req.body.email,req.body.phoneNumber,req.body.role,req.body.address,req.body.createdDate]; - pool.query('insert into users (first_name,middle_name,last_name,email,phone_number,role,address,created_date) values ($1,$2,$3,$4,$5,$6,$7,$8)',data,(q_err:any,q_res:any)=>{ + pool.query('insert into users (firstName,middleName,lastName,email,phoneNumber,role,address,createdDate) values ($1,$2,$3,$4,$5,$6,$7,$8)',data,(q_err:any,q_res:any)=>{ if(q_err){ console.log(q_err); res.code = 404 @@ -38,7 +38,7 @@ export const createUser = (req:any,res:any)=>{ export const updateUser = (req:any,res:any)=>{ const {id} = req.params const data = [req.body.firstName,req.body.middleName,req.body.lastName,req.body.email,req.body.phoneNumber,req.body.role,req.body.address,req.body.createdDate]; - pool.query('UPDATE users SET first_name=$1,middle_name=$2, last_name=$3, email=$4, phone_number=$5, role=$6, address=$7, created_date=$8 WHERE user_id=$9',[...data,id],(q_err:any,q_res:any)=>{ + pool.query('UPDATE users SET firstName=$1,middleName=$2, lastName=$3, email=$4, phoneNumber=$5, role=$6, address=$7, createdDate=$8 WHERE userId=$9',[...data,id],(q_err:any,q_res:any)=>{ if(q_err){ console.log(q_err); res.code = 404 diff --git a/server/src/index.ts b/server/src/index.ts index 1804466..913337c 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -6,6 +6,6 @@ const app = express(); app.use(express.json({limit: "30mb"})); app.use(cors()); -app.use('/user',router); +app.use('/users',router); app.listen(9010); \ No newline at end of file diff --git a/server/src/models/schema.sql b/server/src/models/schema.sql index f6294ba..d0c7134 100644 --- a/server/src/models/schema.sql +++ b/server/src/models/schema.sql @@ -2,14 +2,14 @@ CREATE TYPE roleType AS ENUM ('SuperAdmin', 'Admin', 'Subscriber') DEFAULT 'Subscriber'; CREATE TABLE users( - user_id uuid DEFAULT uuid_generate_v4 () PRIMARY KEY, - first_name VARCHAR(255) NOT NULL, - middle_name VARCHAR(255), - last_name VARCHAR(255) NOT NULL, + userId uuid DEFAULT uuid_generate_v4 () PRIMARY KEY, + firstName VARCHAR(255) NOT NULL, + middleName VARCHAR(255), + lastName VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, - phone_number BIGINT NOT NULL, + phoneNumber BIGINT NOT NULL, role roleType, address VARCHAR(255) NOT NULL, - created_date VARCHAR(255) + createdDate VARCHAR(255) );