working #29

Merged
derek merged 6 commits from working into main 2025-08-18 20:58:14 -07:00
14 changed files with 329 additions and 190 deletions
-3
View File
@@ -24,9 +24,6 @@ Server:
Server.csproj: Server.csproj:
Find a way to keep all the libraries up to date Find a way to keep all the libraries up to date
DbDriver:
Make getConnection() -> Based on a connection pool so that more than a specific number of connections cannot be made
Client: Client:
jobs/editor: jobs/editor:
Job Listing Skills exists but isn't implimented in the UI Job Listing Skills exists but isn't implimented in the UI
+7 -2
View File
@@ -1,13 +1,18 @@
import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core'; import { ApplicationConfig, inject, provideAppInitializer, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router'; import { provideRouter } from '@angular/router';
import { routes } from './app.routes'; import { routes } from './app.routes';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { Authentication } from './services/Authentication';
export const appConfig: ApplicationConfig = { export const appConfig: ApplicationConfig = {
providers: [ providers: [
provideBrowserGlobalErrorListeners(), provideBrowserGlobalErrorListeners(),
provideZoneChangeDetection({ eventCoalescing: true }), provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes), provideRouter(routes),
provideHttpClient(withInterceptorsFromDi()) provideHttpClient(withInterceptorsFromDi()),
provideAppInitializer(async () => {
const auth = inject(Authentication);
return auth.loadLoginState();
})
] ]
}; };
+8 -18
View File
@@ -1,4 +1,4 @@
import { Component, ElementRef, ViewChild } from '@angular/core'; import { Component } from '@angular/core';
import { Router, RouterModule, RouterOutlet, ActivatedRoute } from '@angular/router'; import { Router, RouterModule, RouterOutlet, ActivatedRoute } from '@angular/router';
import { Authentication } from './services/Authentication'; import { Authentication } from './services/Authentication';
import { CommonModule, Location } from '@angular/common'; import { CommonModule, Location } from '@angular/common';
@@ -14,32 +14,22 @@ import { isDevMode } from '@angular/core';
export class App { export class App {
devMode: boolean = false; devMode: boolean = false;
loginToken: string | null = null;
constructor( private http: HttpClient, public auth: Authentication, private router: Router, private route: ActivatedRoute, private location: Location){ constructor( private http: HttpClient, public auth: Authentication, private router: Router, private route: ActivatedRoute, private location: Location){
this.devMode = isDevMode(); this.devMode = isDevMode();
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
const loginToken = params['LoginToken']; this.loginToken = params['LoginToken'];
console.log("LoginToken : " + loginToken); console.log("LoginToken : " + this.loginToken);
if (loginToken){ if (this.loginToken){
this.http.post( "api/account/loginticket", JSON.stringify(loginToken), { headers: {'Content-Type': 'application/json'} } ).subscribe({ this.http.post( "api/account/loginticket", JSON.stringify(this.loginToken), { headers: {'Content-Type': 'application/json'} } ).subscribe({
next: data => { next: async() => {
auth.getLoginState(); await this.auth.loadLoginState();
const pathWithoutQuery = this.location.path().split('?')[0];
this.location.replaceState(pathWithoutQuery);
},
error: err => {
auth.getLoginState();
const pathWithoutQuery = this.location.path().split('?')[0]; const pathWithoutQuery = this.location.path().split('?')[0];
this.location.replaceState(pathWithoutQuery); this.location.replaceState(pathWithoutQuery);
} }
}) })
}else{
auth.getLoginState();
} }
}); });
} }
} }
@@ -28,12 +28,13 @@ export class CompanyComponent {
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
this.title.setTitle("Companies | BoredCareers"); this.title.setTitle("Companies | BoredCareers");
if (!auth.isLoggedIn){ if (!auth.isLoggedIn){
router.navigate(["/"]); router.navigate(["/"]);
} }
};
http.get<Employee[]>("api/employee/").subscribe({ ngOnInit(){
this.http.get<Employee[]>("api/employee/").subscribe({
next: data => { next: data => {
this.Employers = data; this.Employers = data;
if (data[0] != null){ if (data[0] != null){
@@ -46,7 +47,7 @@ export class CompanyComponent {
this.ErrorMsg = err.error; this.ErrorMsg = err.error;
} }
}); });
}; }
changeSelectedCompany(companyID: number){ changeSelectedCompany(companyID: number){
this.http.get<Company>("api/company?CompanyID=" + companyID).subscribe({ this.http.get<Company>("api/company?CompanyID=" + companyID).subscribe({
@@ -24,14 +24,15 @@ export class CompanyEditorComponent {
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
this.title.setTitle("Company - Editor | BoredCareers"); this.title.setTitle("Company - Editor | BoredCareers");
if (!auth.isLoggedIn){ if (!auth.isLoggedIn){
router.navigate(["/"]); router.navigate(["/"]);
} }
};
ngOnInit(){
// Query param CompanyID -> Edit // Query param CompanyID -> Edit
// Query param null -> New // Query param null -> New
}; }
ngAfterViewInit(){ ngAfterViewInit(){
this.formSteps.changes.subscribe(() => { this.formSteps.changes.subscribe(() => {
@@ -26,11 +26,12 @@ export class JobEditorComponent {
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
this.title.setTitle("Jobs - Editor | BoredCareers"); this.title.setTitle("Jobs - Editor | BoredCareers");
if (!auth.isLoggedIn){ if (!auth.isLoggedIn){
router.navigate(["/"]); router.navigate(["/"]);
} }
}
ngOnInit(){
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
const CompanyID = params['CompanyID'] ? +params['CompanyID'] : null; const CompanyID = params['CompanyID'] ? +params['CompanyID'] : null;
const JobID = params['JobID'] ? +params['JobID'] : null; const JobID = params['JobID'] ? +params['JobID'] : null;
@@ -23,12 +23,10 @@ export class JobsComponent {
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
this.title.setTitle("Jobs | BoredCareers"); this.title.setTitle("Jobs | BoredCareers");
};
if (this.Page == 1){ ngOnInit(){
this.http.get<JobListing[]>("api/joblisting?PageQuantity=" + 10 + "&Page=" + 1).subscribe({
}
http.get<JobListing[]>("api/joblisting?PageQuantity=" + 10 + "&Page=" + 1).subscribe({
next: data => { next: data => {
this.JobListingPage = data; this.JobListingPage = data;
}, },
@@ -36,7 +34,6 @@ export class JobsComponent {
this.ErrorMsg = err.error; this.ErrorMsg = err.error;
} }
}); });
}
};
} }
@@ -22,7 +22,9 @@ export class JobViewerComponent {
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
this.title.setTitle("Jobs - Viewer | BoredCareers"); this.title.setTitle("Jobs - Viewer | BoredCareers");
};
ngOnInit(){
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
const JobID = params['JobID']; const JobID = params['JobID'];
if (JobID){ if (JobID){
@@ -43,13 +45,12 @@ export class JobViewerComponent {
} }
}) })
}else{ }else{
router.navigate(["/"]); this.router.navigate(["/"]);
} }
if (this.selectedJob != null){ if (this.selectedJob != null){
} }
}); });
}
};
} }
@@ -1,10 +1,106 @@
input, textarea {
border: 1px solid #444;
background-color: transparent;
}
textarea {
resize: vertical;
}
h1 {
margin: 0;
font-size: 15px;
}
.paper {
width: 800px;
aspect-ratio: 17 / 22;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
margin: auto;
margin-top: 50px;
border: 1px solid #ddd;
}
.spacer {
margin: 0 10px;
}
.spacer-title {
display: flex;
margin: 10px 0;
}
.columns {
columns: 2;
column-gap: 10px;
}
.resume-header {
width: 70vw;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
margin: auto;
margin-top: 50px;
border: 1px solid #ddd;
}
.resume-section { .resume-section {
break-inside: avoid;
background-color: #DDDDDD; background-color: #DDDDDD;
margin: 10px; margin-bottom: 10px;
} }
.resume-sub-section { .resume-sub-section {
border: 1px solid #666666; border: 1px solid #666666;
margin: 5px;
padding: 10px; padding: 10px;
} }
.title-text {
margin: 0;
height: 20px;
}
.header-left {
width: 50%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
}
.header-right {
width: 50%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-end;
}
.header-location input{
width: 80px;
}
.Add {
position: relative;
float: right;
width: 20px;
height: 20px;
background-color: #0F0;
border: none;
bottom: 20px;
}
.Del {
position: relative;
float: right;
width: 20px;
height: 20px;
background-color: #F00;
border: none;
}
.flex-two-row {
display: flex;
flex: 1;
}
@@ -1,140 +1,170 @@
<form (ngSubmit)="SubmitForm(resume)"> <form (ngSubmit)="SubmitForm(resume)">
<div class="resume-header">
<!-- Resume Header --> <div>
<div class="resume-section"> <input [name]="'resumetitle' + resume.trackUUID" [(ngModel)]="resume.title" type="text" placeholder="Resume Name" />
<input [name]="'resumetitle' + resume.trackUUID" [(ngModel)]="resume.title" type="text" placeholder="Resume 1" /> </div>
<input [name]="'resumename' + resume.trackUUID" [(ngModel)]="resume.name" type="text" placeholder="John Doe" />
<input [name]="'resumefield' + resume.trackUUID" [(ngModel)]="resume.field" type="text" placeholder="Data Scientist" />
<input [name]="'resumeemail' + resume.trackUUID" [(ngModel)]="resume.email" type="email" placeholder="no-reply@mistox.com" />
<input [name]="'resumephoneNumber' + resume.trackUUID" [(ngModel)]="resume.phoneNumber" type="tel" placeholder="+1 800-000-0000" />
<input [name]="'resumepostalCode' + resume.trackUUID" [(ngModel)]="resume.postalCode" type="text" placeholder="92020" />
<input [name]="'resumecountry' + resume.trackUUID" [(ngModel)]="resume.country" type="text" placeholder="US" />
<input [name]="'resumestateOrRegion' + resume.trackUUID" [(ngModel)]="resume.stateOrRegion" type="text" placeholder="CA" />
<input [name]="'resumecity' + resume.trackUUID" [(ngModel)]="resume.city" type="text" placeholder="San Diego" />
<h1>Public: </h1><input [name]="'active' + resume.trackUUID" [(ngModel)]="resume.isActive" type="checkbox" /> <h1>Public: </h1><input [name]="'active' + resume.trackUUID" [(ngModel)]="resume.isActive" type="checkbox" />
<h1>Is Veteran: </h1><input [name]="'veteran' + resume.military?.trackUUID" type="checkbox" [checked]="resume.military !== null" (change)="onVeteranChange($event)" />
<button type="button" (click)="PrintResume()">Print</button>
</div> </div>
<div class="paper">
<div class="spacer">
<!-- Resume Header -->
<div class="resume-section spacer-title">
<div class="header-left">
<input [name]="'resumename' + resume.trackUUID" [(ngModel)]="resume.name" type="text" placeholder="Full Name" />
<input [name]="'resumefield' + resume.trackUUID" [(ngModel)]="resume.field" type="text" placeholder="Career Field" />
<div class="header-location">
<input [name]="'resumecity' + resume.trackUUID" [(ngModel)]="resume.city" type="text" placeholder="City" />
<input [name]="'resumestateOrRegion' + resume.trackUUID" [(ngModel)]="resume.stateOrRegion" type="text" placeholder="State" />
<input [name]="'resumecountry' + resume.trackUUID" [(ngModel)]="resume.country" type="text" placeholder="Country" />
<input [name]="'resumepostalCode' + resume.trackUUID" [(ngModel)]="resume.postalCode" type="text" placeholder="Postal Code" />
</div>
</div>
<div class="header-right">
<input [name]="'resumeemail' + resume.trackUUID" [(ngModel)]="resume.email" type="email" placeholder="Email Address" />
<input [name]="'resumephoneNumber' + resume.trackUUID" [(ngModel)]="resume.phoneNumber" type="tel" placeholder="Phone number" />
</div>
</div>
<div class="columns">
<!-- Experience --> <!-- Experience -->
<div class="resume-section"> <div class="resume-section">
<button type="button" (click)="addExperience()">ADD Experience</button> <h1 class="title-text">Experience</h1>
@for(experience of resume.experiences; track experience.trackUUID ){ @for(experience of resume.experiences; track experience.trackUUID ){
<button class="Del" type="button" (click)="delExperience(experience)">X</button>
<div class="resume-sub-section"> <div class="resume-sub-section">
<input [name]="'experiencejobTitle' + experience.trackUUID" [(ngModel)]="experience.jobTitle" type="text" placeholder="Data Entry Clerk" /> <input [name]="'experiencejobTitle' + experience.trackUUID" [(ngModel)]="experience.jobTitle" type="text" placeholder="Job Title" />
<input [name]="'experiencecompany' + experience.trackUUID" [(ngModel)]="experience.company" type="text" placeholder="San Diego Gas Electric" /> <input [name]="'experiencecompany' + experience.trackUUID" [(ngModel)]="experience.company" type="text" placeholder="Company" />
<input [name]="'experiencepostalCode' + experience.trackUUID" [(ngModel)]="experience.postalCode" type="text" placeholder="92020" /> <input [name]="'experiencecity' + experience.trackUUID" [(ngModel)]="experience.city" type="text" placeholder="City" />
<input [name]="'experiencecountry' + experience.trackUUID" [(ngModel)]="experience.country" type="text" placeholder="US" /> <input [name]="'experiencestateOrRegion' + experience.trackUUID" [(ngModel)]="experience.stateOrRegion" type="text" placeholder="State" />
<input [name]="'experiencestateOrRegion' + experience.trackUUID" [(ngModel)]="experience.stateOrRegion" type="text" placeholder="CA" /> <input [name]="'experiencecountry' + experience.trackUUID" [(ngModel)]="experience.country" type="text" placeholder="Country" />
<input [name]="'experiencecity' + experience.trackUUID" [(ngModel)]="experience.city" type="text" placeholder="San Diego" /> <input [name]="'experiencepostalCode' + experience.trackUUID" [(ngModel)]="experience.postalCode" type="text" placeholder="Postal Code" />
<input [name]="'experiencedateStarted' + experience.trackUUID" [(ngModel)]="experience.dateStarted" type="date" />
<input [name]="'experiencestillEmployed' + experience.trackUUID" [(ngModel)]="experience.stillEmployed" type="checkbox" /> <input [name]="'experiencestillEmployed' + experience.trackUUID" [(ngModel)]="experience.stillEmployed" type="checkbox" />
<input [name]="'experiencedateStarted' + experience.trackUUID" [(ngModel)]="experience.dateStarted" type="date" />
@if(!experience.stillEmployed){ @if(!experience.stillEmployed){
<input [name]="'experiencedateEnded' + experience.trackUUID" [(ngModel)]="experience.dateEnded" type="date" /> <input [name]="'experiencedateEnded' + experience.trackUUID" [(ngModel)]="experience.dateEnded" type="date" />
} }
<button type="button" (click)="addJobFunction(experience)">Add jobFunction</button> <button type="button" (click)="addJobFunction(experience)">Add jobFunction</button>
@for(bullet of experience.experienceBullets; track bullet.trackUUID){ @for(bullet of experience.experienceBullets; track bullet.trackUUID){
<div> <div>
<textarea [name]="'bulletjobFunction' + bullet.trackUUID" [(ngModel)]="bullet.jobFunction" placeholder="Processed database transactions" ></textarea>
<button type="button" (click)="delJobFunction(experience, bullet)">DEL jobFunction</button> <button type="button" (click)="delJobFunction(experience, bullet)">DEL jobFunction</button>
<textarea [name]="'bulletjobFunction' + bullet.trackUUID" [(ngModel)]="bullet.jobFunction" placeholder="Job Task / Function" ></textarea>
</div> </div>
} }
<button type="button" (click)="delExperience(experience)">DEL Experience</button>
</div> </div>
} }
<button class="Add" type="button" (click)="addExperience()">+</button>
</div> </div>
<!-- Military --> <!-- Military -->
<div class="resume-section">
<h1>Is Veteran: </h1><input [name]="'veteran' + resume.military?.trackUUID" type="checkbox" (change)="onVeteranChange($event)" />
@if(resume.military !== null){ @if(resume.military !== null){
<input [name]="'militarycountry' + resume.military.trackUUID" [(ngModel)]="resume.military.country" type="text" placeholder="US" /> <div class="resume-section">
<input [name]="'militaryrank' + resume.military.trackUUID" [(ngModel)]="resume.military.rank" type="text" placeholder="PVT" /> <h1 class="title-text">Military</h1>
<input [name]="'militarydateStarted' + resume.military.trackUUID" [(ngModel)]="resume.military.dateStarted" type="date" /> <input [name]="'militarycountry' + resume.military.trackUUID" [(ngModel)]="resume.military.country" type="text" placeholder="Country" />
<input [name]="'militaryrank' + resume.military.trackUUID" [(ngModel)]="resume.military.rank" type="text" placeholder="Rank" />
<h1>Still Serving: </h1><input [name]="'stillServing' + resume.military.trackUUID" [(ngModel)]="resume.military.stillServing" type="checkbox" /> <h1>Still Serving: </h1><input [name]="'stillServing' + resume.military.trackUUID" [(ngModel)]="resume.military.stillServing" type="checkbox" />
<input [name]="'militarydateStarted' + resume.military.trackUUID" [(ngModel)]="resume.military.dateStarted" type="date" />
@if (!resume.military.stillServing){ @if (!resume.military.stillServing){
<input [name]="'dateEnded' + resume.military.trackUUID" [(ngModel)]="resume.military.dateEnded" type="date" /> <input [name]="'dateEnded' + resume.military.trackUUID" [(ngModel)]="resume.military.dateEnded" type="date" />
} }
<button type="button" (click)="addMillitaryBullet()">Add Millitary Task</button> <button type="button" (click)="addMillitaryBullet()">Add Millitary Task</button>
@for(military of resume.military.militaryBullets; track military.trackUUID ){ @for(military of resume.military.militaryBullets; track military.trackUUID ){
<div> <div class="resume-sub-section">
<input [name]="'militaryachievement' + military.trackUUID" [(ngModel)]="military.achievement" type="text" placeholder="Deployed Kuwait" />
<textarea [name]="'militarydescription' + military.trackUUID" [(ngModel)]="military.description" placeholder="Delivered goods line-hall" ></textarea>
<button type="button" (click)="delMillitaryBullet(military)">DEL Military Task</button> <button type="button" (click)="delMillitaryBullet(military)">DEL Military Task</button>
<input [name]="'militaryachievement' + military.trackUUID" [(ngModel)]="military.achievement" type="text" placeholder="Achievement" />
<textarea [name]="'militarydescription' + military.trackUUID" [(ngModel)]="military.description" placeholder="Description" ></textarea>
</div> </div>
} }
}
</div> </div>
}
<!-- Education --> <!-- Education -->
<div class="resume-section"> <div class="resume-section">
<button type="button" (click)="addEducation()">ADD Education</button> <h1 class="title-text">Education</h1>
@for(education of resume.educations; track education.trackUUID){ @for(education of resume.educations; track education.trackUUID){
<div> <button class="Del" type="button" (click)="delEducation(education)">X</button>
<input [name]="'educationdegreeType' + education.trackUUID" [(ngModel)]="education.degreeType" type="text" placeholder="Masters" /> <div class="resume-sub-section">
<input [name]="'educationdegreeField' + education.trackUUID" [(ngModel)]="education.degreeField" type="text" placeholder="Computer Science" /> <input [name]="'educationschool' + education.trackUUID" [(ngModel)]="education.school" type="text" placeholder="School" />
<input [name]="'educationschool' + education.trackUUID" [(ngModel)]="education.school" type="text" placeholder="WGU" /> <input [name]="'educationdegreeType' + education.trackUUID" [(ngModel)]="education.degreeType" type="text" placeholder="Type" />
<input [name]="'educationpostalCode' + education.trackUUID" [(ngModel)]="education.postalCode" type="text" placeholder="84107" /> <input [name]="'educationdegreeField' + education.trackUUID" [(ngModel)]="education.degreeField" type="text" placeholder="Field" />
<input [name]="'educationcountry' + education.trackUUID" [(ngModel)]="education.country" type="text" placeholder="US" /> <input [name]="'educationcity' + education.trackUUID" [(ngModel)]="education.city" type="text" placeholder="City" />
<input [name]="'educationstateOrRegion' + education.trackUUID" [(ngModel)]="education.stateOrRegion" type="text" placeholder="UT" /> <input [name]="'educationstateOrRegion' + education.trackUUID" [(ngModel)]="education.stateOrRegion" type="text" placeholder="State" />
<input [name]="'educationcity' + education.trackUUID" [(ngModel)]="education.city" type="text" placeholder="Salt Lake City" /> <input [name]="'educationcountry' + education.trackUUID" [(ngModel)]="education.country" type="text" placeholder="Country" />
<input [name]="'educationdateStarted' + education.trackUUID" [(ngModel)]="education.dateStarted" type="date" /> <input [name]="'educationpostalCode' + education.trackUUID" [(ngModel)]="education.postalCode" type="text" placeholder="Postal Code" />
<input [name]="'educationstillStudying' + education.trackUUID" [(ngModel)]="education.stillStudying" type="checkbox" /> <input [name]="'educationstillStudying' + education.trackUUID" [(ngModel)]="education.stillStudying" type="checkbox" />
<input [name]="'educationdateStarted' + education.trackUUID" [(ngModel)]="education.dateStarted" type="date" />
@if (!education.stillStudying){ @if (!education.stillStudying){
<input [name]="'educationdateEnded' + education.trackUUID" [(ngModel)]="education.dateEnded" type="date" /> <input [name]="'educationdateEnded' + education.trackUUID" [(ngModel)]="education.dateEnded" type="date" />
} }
<button type="button" (click)="delEducation(education)">DEL Education</button>
</div> </div>
} }
<button class="Add" type="button" (click)="addEducation()">+</button>
</div> </div>
<!-- Skill --> <!-- Skill -->
<div class="resume-section"> <div class="resume-section">
<button type="button" (click)="addSkill()">ADD Skill</button> <h1 class="title-text">Skills</h1>
@for(skill of resume.skills; track skill.trackUUID){ @for(skill of resume.skills; track skill.trackUUID){
<button class="Del" type="button" (click)="delSkill(skill)">X</button>
<div class="resume-sub-section flex-two-row">
<div> <div>
<input [name]="'skillname' + skill.trackUUID" [(ngModel)]="skill.name" type="text" placeholder="Angular JS" /> <input [name]="'skillname' + skill.trackUUID" [(ngModel)]="skill.name" type="text" placeholder="Skill" />
<textarea [name]="'skilldescription' + skill.trackUUID" [(ngModel)]="skill.description" placeholder="Built this entire website using Angular JS"></textarea> </div>
<button type="button" (click)="delSkill(skill)">DEL Skill</button> <textarea [name]="'skilldescription' + skill.trackUUID" [(ngModel)]="skill.description" placeholder="Description"></textarea>
</div> </div>
} }
<button class="Add" type="button" (click)="addSkill()">+</button>
</div> </div>
<!-- Language --> <!-- Language -->
<div class="resume-section"> <div class="resume-section">
<button type="button" (click)="addLanguage()">ADD Language</button> <h1 class="title-text">Languages</h1>
@for(language of resume.languages; track language.trackUUID){ @for(language of resume.languages; track language.trackUUID){
<div> <button class="Del" type="button" (click)="delLanguage(language)">X</button>
<input [name]="'languagelanguage' + language.trackUUID" [(ngModel)]="language.language" type="text" placeholder="Spanish" /> <div class="resume-sub-section flex-two-row">
<input [name]="'languageproficiency' + language.trackUUID" [(ngModel)]="language.proficiency" type="text" placeholder="casual speaking" /> <input [name]="'languagelanguage' + language.trackUUID" [(ngModel)]="language.language" type="text" placeholder="Language" />
<button type="button" (click)="delLanguage(language)">DEL Language</button> <input [name]="'languageproficiency' + language.trackUUID" [(ngModel)]="language.proficiency" type="text" placeholder="Proficiency" />
</div> </div>
} }
<button class="Add" type="button" (click)="addLanguage()">+</button>
</div> </div>
<!-- Certification --> <!-- Certification -->
<div class="resume-section"> <div class="resume-section">
<button type="button" (click)="addCert()">ADD Certification</button> <h1 class="title-text">Certifications</h1>
@for(cert of resume.certifications; track cert.trackUUID){ @for(cert of resume.certifications; track cert.trackUUID){
<button class="Del" type="button" (click)="delCert(cert)">X</button>
<div class="resume-sub-section flex-two-row">
<div> <div>
<input [name]="'certname' + cert.trackUUID" [(ngModel)]="cert.name" type="text" placeholder="Comptia A+" /> <input [name]="'certname' + cert.trackUUID" [(ngModel)]="cert.name" type="text" placeholder="Certification Name" />
<input [name]="'certverificationURL' + cert.trackUUID" [(ngModel)]="cert.verificationURL" type="text" placeholder="https://certmaster.com/certid" /> <input [name]="'certverificationURL' + cert.trackUUID" [(ngModel)]="cert.verificationURL" type="text" placeholder="Verification URL" />
<textarea [name]="'certdescription' + cert.trackUUID" [(ngModel)]="cert.description" placeholder="Into to information technology"></textarea> </div>
<button type="button" (click)="delCert(cert)">DEL Certification</button> <textarea [name]="'certdescription' + cert.trackUUID" [(ngModel)]="cert.description" placeholder="Description"></textarea>
</div> </div>
} }
<button class="Add" type="button" (click)="addCert()">+</button>
</div> </div>
<!-- Project --> <!-- Project -->
<div class="resume-section"> <div class="resume-section">
<button type="button" (click)="addProject()">ADD Project</button> <h1 class="title-text">Projects</h1>
@for(proj of resume.projects; track proj.trackUUID){ @for(proj of resume.projects; track proj.trackUUID){
<button class="Del" type="button" (click)="delProject(proj)">X</button>
<div class="resume-sub-section flex-two-row">
<div> <div>
<input [name]="'projname' + proj.trackUUID" [(ngModel)]="proj.name" type="text" placeholder="boredcareers" /> <input [name]="'projname' + proj.trackUUID" [(ngModel)]="proj.name" type="text" placeholder="Project Name" />
<input [name]="'projurl' + proj.trackUUID" [(ngModel)]="proj.url" type="text" placeholder="mistox.com" /> <input [name]="'projurl' + proj.trackUUID" [(ngModel)]="proj.url" type="text" placeholder="Reference URL" />
<textarea [name]="'projdescription' + proj.trackUUID" [(ngModel)]="proj.description" placeholder="the project that your currently viewing"></textarea> </div>
<button type="button" (click)="delProject(proj)">DEL Project</button> <textarea [name]="'projdescription' + proj.trackUUID" [(ngModel)]="proj.description" placeholder="Description"></textarea>
</div> </div>
} }
<button class="Add" type="button" (click)="addProject()">+</button>
</div>
</div>
</div>
</div> </div>
@if (isNewResume){ @if (isNewResume){
@@ -6,7 +6,6 @@ import { Title } from '@angular/platform-browser';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Resume, ResumeCertification, ResumeEducation, ResumeExperience, ResumeExperienceBullet, ResumeLanguage, ResumeMilitary, ResumeMilitaryBullet, ResumeProject, ResumeSkill } from 'app/models/Resume'; import { Resume, ResumeCertification, ResumeEducation, ResumeExperience, ResumeExperienceBullet, ResumeLanguage, ResumeMilitary, ResumeMilitaryBullet, ResumeProject, ResumeSkill } from 'app/models/Resume';
import { Authentication } from 'app/services/Authentication'; import { Authentication } from 'app/services/Authentication';
import { HomeComponent } from "app/pages/home/home.component";
@Component({ @Component({
selector: 'main-resume-editor', selector: 'main-resume-editor',
@@ -23,11 +22,13 @@ export class ResumesEditorComponent {
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
this.title.setTitle("Resume - Editor | BoredCareers"); this.title.setTitle("Resume - Editor | BoredCareers");
if (!auth.isLoggedIn){ if (!this.auth.isLoggedIn){
router.navigate(["/"]); this.router.navigate(["/"]);
} }
this.route.queryParams.subscribe(params => { };
ngOnInit(){
this.route.queryParams.subscribe(params => {
const ResumeID = params['ResumeID'] ? +params['ResumeID'] : null; const ResumeID = params['ResumeID'] ? +params['ResumeID'] : null;
if (ResumeID !== null){ if (ResumeID !== null){
this.http.get<Resume>("api/resume?ResumeID=" + ResumeID).subscribe({ this.http.get<Resume>("api/resume?ResumeID=" + ResumeID).subscribe({
@@ -42,7 +43,12 @@ export class ResumesEditorComponent {
}); });
} }
}); });
}; }
// Pagnation //
////////////////////////////////
////////////////////////////////
SubmitForm(resume: Resume){ SubmitForm(resume: Resume){
resume.accountID = this.auth.loggedInUser.id; resume.accountID = this.auth.loggedInUser.id;
@@ -56,6 +62,22 @@ export class ResumesEditorComponent {
}); });
} }
PrintResume(){
const divToPrint = document.getElementsByClassName("paper")[0];
const printContents = divToPrint.innerHTML;
const originalContents = document.body.innerHTML; // Store original body content
// Temporarily replace the body content with the div's content
document.body.innerHTML = printContents;
// Trigger the print dialog
window.print();
// Restore the original body content
document.body.innerHTML = originalContents;
}
addExperience(){ addExperience(){
this.resume.experiences.push( new ResumeExperience ); this.resume.experiences.push( new ResumeExperience );
} }
@@ -1,7 +1,7 @@
<div class="top-bar"> <div class="top-bar">
@for(resume of myResumes; track myResumes.length){ @for(resume of myResumes; track myResumes.length){
@if (resume.id != null){ @if (resume.id != null){
<button (click)="changeSelectedResume(resume.id)">{{ resume.title }}</button> <button [routerLink]="['/resumes/editor']" [queryParams]="{ ResumeID: resume.id }" >{{ resume.title }}</button>
} }
} }
<button routerLink="/resumes/editor" >NEW RESUME</button> <button routerLink="/resumes/editor" >NEW RESUME</button>
@@ -20,11 +20,12 @@ export class ResumesComponent {
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
this.title.setTitle("Resumes | BoredCareers"); this.title.setTitle("Resumes | BoredCareers");
if (!auth.isLoggedIn){ if (!auth.isLoggedIn){
router.navigate(["/"]); router.navigate(["/"]);
} }
};
ngOnInit(){
this.http.get<Resume[]>("api/resume").subscribe({ this.http.get<Resume[]>("api/resume").subscribe({
next: data => { next: data => {
this.myResumes = data; this.myResumes = data;
@@ -33,7 +34,7 @@ export class ResumesComponent {
console.log("Error fetching resumes: " + err.error); console.log("Error fetching resumes: " + err.error);
} }
}); });
}; }
changeSelectedResume(ResumeID: number){ changeSelectedResume(ResumeID: number){
this.http.get<Resume>("api/resume?ResumeID=" + ResumeID).subscribe({ this.http.get<Resume>("api/resume?ResumeID=" + ResumeID).subscribe({
+9 -12
View File
@@ -1,7 +1,7 @@
import { Injectable } from "@angular/core"; import { Injectable } from "@angular/core";
import { Account } from "../models/Account"; import { Account } from "../models/Account";
import { BehaviorSubject, Observable } from "rxjs"; import { BehaviorSubject, firstValueFrom } from "rxjs";
import { HttpClient } from "@angular/common/http"; import { HttpClient, HttpErrorResponse } from "@angular/common/http";
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class Authentication{ export class Authentication{
@@ -11,17 +11,14 @@ export class Authentication{
constructor( private http: HttpClient){ } constructor( private http: HttpClient){ }
getLoginState(): Observable<Account> { async loadLoginState(): Promise<void> {
let sub = this.http.post<Account>( "api/account/loginState", {}, {} ); try {
sub.subscribe({ this._user.next( await firstValueFrom(this.http.post<Account>( "api/account/loginState", {}, {} )) );
next: data => { } catch (err: unknown){
this._user.next(data); if (err instanceof HttpErrorResponse) {
}, console.error( err.error );
error: err => { }
console.log("No login state found: ", err.error);
} }
});
return sub;
} }
Logout(){ Logout(){