working #36
@@ -12,9 +12,10 @@ Server:
|
|||||||
Need to update notification email
|
Need to update notification email
|
||||||
Create page to notify cx that their work email has been verified
|
Create page to notify cx that their work email has been verified
|
||||||
|
|
||||||
|
Verify that each resume section belongs to the resume it was created for:
|
||||||
|
|
||||||
Client:
|
Client:
|
||||||
jobs/editor:
|
jobs/editor:
|
||||||
Job Listing Skills exists but isn't implimented in the UI
|
|
||||||
Want to add completed job listing preview at end of carosel
|
Want to add completed job listing preview at end of carosel
|
||||||
|
|
||||||
Resume:
|
Resume:
|
||||||
@@ -27,6 +28,11 @@ Client:
|
|||||||
Allow users to look up jobs and apply [ Boost visibility | Completely manual ]
|
Allow users to look up jobs and apply [ Boost visibility | Completely manual ]
|
||||||
Mark ghost listings to allow users to be informed and put companies on blast
|
Mark ghost listings to allow users to be informed and put companies on blast
|
||||||
|
|
||||||
|
resume/viewer:
|
||||||
|
CSS is broken
|
||||||
|
Company needs to be able to add notes to resume
|
||||||
|
Company needs to be able to add a rating to the resume
|
||||||
|
|
||||||
company/editor:
|
company/editor:
|
||||||
Keyboard Tab key does nothing
|
Keyboard Tab key does nothing
|
||||||
Format phone number for database
|
Format phone number for database
|
||||||
@@ -36,6 +42,10 @@ Client:
|
|||||||
resume/editor:
|
resume/editor:
|
||||||
There is no data validation
|
There is no data validation
|
||||||
|
|
||||||
|
application/viewer:
|
||||||
|
need to make look better for companies to sort
|
||||||
|
need to show notes and rating properly
|
||||||
|
|
||||||
Company:
|
Company:
|
||||||
Need to impliment Add employee
|
Need to impliment Add employee
|
||||||
Need to impliment Remove employee
|
Need to impliment Remove employee
|
||||||
|
|||||||
@@ -8,15 +8,21 @@ import { CompanyEditorComponent } from './pages/company/editor/editor.component'
|
|||||||
import { JobViewerComponent } from './pages/jobs/viewer/jobviewer.component';
|
import { JobViewerComponent } from './pages/jobs/viewer/jobviewer.component';
|
||||||
import { CompanyComponent } from './pages/company/company.component';
|
import { CompanyComponent } from './pages/company/company.component';
|
||||||
import { ResumesEditorComponent } from './pages/resumes/editor/editor.component';
|
import { ResumesEditorComponent } from './pages/resumes/editor/editor.component';
|
||||||
|
import { AppViewerComponent } from './pages/applicationviewer/appviewer.component';
|
||||||
|
import { ResumesViewerComponent } from './pages/resumes/viewer/viewer.component';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
|
|
||||||
// Home
|
// Home
|
||||||
{ path: "", component: HomeComponent },
|
{ path: "", component: HomeComponent },
|
||||||
|
|
||||||
|
// Application
|
||||||
|
{ path: "application/viewer", component: AppViewerComponent },
|
||||||
|
|
||||||
// Resumes
|
// Resumes
|
||||||
{ path: "resumes", component: ResumesComponent },
|
{ path: "resumes", component: ResumesComponent },
|
||||||
{ path: "resumes/editor", component: ResumesEditorComponent },
|
{ path: "resumes/editor", component: ResumesEditorComponent },
|
||||||
|
{ path: "resumes/viewer", component: ResumesViewerComponent },
|
||||||
|
|
||||||
// Jobs
|
// Jobs
|
||||||
{ path: "jobs", component: JobsComponent },
|
{ path: "jobs", component: JobsComponent },
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ export class App {
|
|||||||
this.devMode = isDevMode();
|
this.devMode = isDevMode();
|
||||||
this.route.queryParams.subscribe(params => {
|
this.route.queryParams.subscribe(params => {
|
||||||
this.loginToken = params['LoginToken'];
|
this.loginToken = params['LoginToken'];
|
||||||
console.log("LoginToken : " + this.loginToken);
|
|
||||||
if (this.loginToken){
|
if (this.loginToken){
|
||||||
this.http.post( "api/account/loginticket", JSON.stringify(this.loginToken), { headers: {'Content-Type': 'application/json'} } ).subscribe({
|
this.http.post( "api/account/loginticket", JSON.stringify(this.loginToken), { headers: {'Content-Type': 'application/json'} } ).subscribe({
|
||||||
next: async() => {
|
next: async() => {
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ export class Application {
|
|||||||
public hasBeenViewed: boolean = false;
|
public hasBeenViewed: boolean = false;
|
||||||
public rating: number = 0;
|
public rating: number = 0;
|
||||||
public notes: string = "";
|
public notes: string = "";
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
@@ -13,4 +13,5 @@ export class Company {
|
|||||||
public stateOrRegion: string = "";
|
public stateOrRegion: string = "";
|
||||||
public city: string = "";
|
public city: string = "";
|
||||||
public description: string = "";
|
public description: string = "";
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
@@ -6,4 +6,5 @@ export class Employee {
|
|||||||
public accountName: string = "";
|
public accountName: string = "";
|
||||||
public accountEmail: string = "";
|
public accountEmail: string = "";
|
||||||
public company: Company = new Company;
|
public company: Company = new Company;
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
@@ -15,11 +15,13 @@ export class JobListing {
|
|||||||
public createdTime: Date = new Date();
|
public createdTime: Date = new Date();
|
||||||
public modifiedTime: Date = new Date();
|
public modifiedTime: Date = new Date();
|
||||||
public isDeleted: boolean = false;
|
public isDeleted: boolean = false;
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class JobListingSkills {
|
export class JobListingSkills {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public jobListingID: number = 0;
|
public jobListingID: number = 0;
|
||||||
public name: string = "";
|
public name: string = "";
|
||||||
public Description: string = "";
|
public description: string = "";
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
button {
|
||||||
|
height: 45px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 10px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 20px;
|
||||||
|
transition: 0.5s;
|
||||||
|
background-color: #00000000;
|
||||||
|
border: 1px solid var(--Mistox-Black);
|
||||||
|
color: var(--Mistox-Black);
|
||||||
|
text-decoration: none;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #00000044;
|
||||||
|
color: var(--Mistox-Light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-frame {
|
||||||
|
background-color: #3c3c3c;
|
||||||
|
width: calc(100% - 40px);
|
||||||
|
height: calc(100vh - 400px);
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
overflow: scroll;
|
||||||
|
padding: 10px;
|
||||||
|
color: var(--Mistox-White);
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-item {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-edit {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-item img {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-name {
|
||||||
|
width: 300px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-name h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-link {
|
||||||
|
display: flex;
|
||||||
|
width: 300px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-link a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--Mistox-White);
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-desc {
|
||||||
|
border: solid 1px red;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 0 100px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-desc h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-button span {
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-frame {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.half-frame {
|
||||||
|
width: 50%;
|
||||||
|
border-right: solid 1px var(--Mistox-Black);
|
||||||
|
border-left: solid 1px var(--Mistox-Black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.half-frame h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-tile {
|
||||||
|
display: flex;
|
||||||
|
background-color: var(--Mistox-Black);
|
||||||
|
justify-content: end;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 0 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-text {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-tile h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-tile button {
|
||||||
|
color: white;
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<div>
|
||||||
|
@for (application of List; track application.trackUUID){
|
||||||
|
<div>
|
||||||
|
<h1>{{ application.responseEmail }}</h1>
|
||||||
|
<h1>{{ application.notes }}</h1>
|
||||||
|
<h1>{{ application.hasBeenViewed }}</h1>
|
||||||
|
<h1>{{ application.rating }}</h1>
|
||||||
|
<h1>{{ application.responseStatus }}</h1>
|
||||||
|
|
||||||
|
<h1>Date Applied: </h1><h1>{{ application.dateApplied }}</h1>
|
||||||
|
|
||||||
|
<button type="button" (click)="viewResume(application)" >VIEW RESUME</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { Router, ActivatedRoute, RouterModule } from '@angular/router';
|
||||||
|
import { Title } from '@angular/platform-browser';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Authentication } from 'app/services/Authentication';
|
||||||
|
import { Application } from 'app/models/Application';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'App-Viewer',
|
||||||
|
templateUrl: './appviewer.component.html',
|
||||||
|
styleUrls: [ './appviewer.component.css' ],
|
||||||
|
imports: [ FormsModule, CommonModule, RouterModule ]
|
||||||
|
})
|
||||||
|
export class AppViewerComponent {
|
||||||
|
public ErrorMsg: string = "";
|
||||||
|
|
||||||
|
public List: Application[] = [];
|
||||||
|
|
||||||
|
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
||||||
|
this.title.setTitle("Applications | BoredCareers");
|
||||||
|
if (!auth.isLoggedIn){
|
||||||
|
router.navigate(["/"]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ngOnInit(){
|
||||||
|
this.route.queryParams.subscribe(params => {
|
||||||
|
const JobListingID = params['JobID'] ? +params['JobID'] : null;
|
||||||
|
if (JobListingID !== null){
|
||||||
|
this.http.get<Application[]>("api/application?JobListingID=" + JobListingID).subscribe({
|
||||||
|
next: data => {
|
||||||
|
this.List = data;
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
this.ErrorMsg = err.error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
viewResume(app: Application) {
|
||||||
|
window.open('/resumes/viewer?ResumeID=' + app.resumeID, '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
<div class="center-text">
|
<div class="center-text">
|
||||||
<h1>{{ listing.title }}</h1>
|
<h1>{{ listing.title }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
<button [routerLink]="['/application/viewer']" [queryParams]="{ JobID: listing.id }" >VIEW LISTING</button>
|
||||||
<button [routerLink]="['/jobs/viewer']" [queryParams]="{ JobID: listing.id }" >VIEW LISTING</button>
|
<button [routerLink]="['/jobs/viewer']" [queryParams]="{ JobID: listing.id }" >VIEW LISTING</button>
|
||||||
<button [routerLink]="['/jobs/editor']" [queryParams]="{ JobID: listing.id }" >EDIT LISTING</button>
|
<button [routerLink]="['/jobs/editor']" [queryParams]="{ JobID: listing.id }" >EDIT LISTING</button>
|
||||||
<button (click)="RemoveJobListing(listing.id!)">DELETE LISTING</button>
|
<button (click)="RemoveJobListing(listing.id!)">DELETE LISTING</button>
|
||||||
|
|||||||
@@ -60,11 +60,11 @@
|
|||||||
<div class="split">
|
<div class="split">
|
||||||
<div class="half-frame">
|
<div class="half-frame">
|
||||||
<label>Company Email</label>
|
<label>Company Email</label>
|
||||||
<input class="input-field" name="email" [(ngModel)]="newListing.email" type="text" placeholder="Questions@mistox.com" />
|
<input class="input-field" name="email" [(ngModel)]="newListing.email" type="text" (ngModelChange)="validateEmail(newListing.email)" placeholder="Questions@mistox.com" />
|
||||||
</div>
|
</div>
|
||||||
<div class="half-frame">
|
<div class="half-frame">
|
||||||
<label>Company Phone Number</label>
|
<label>Company Phone Number</label>
|
||||||
<input class="input-field" name="phone" [(ngModel)]="newListing.phone" type="text" placeholder="+1 800-000-0000" />
|
<input class="input-field" name="phone" [(ngModel)]="newListing.phone" type="tel" (ngModelChange)="validatePhone(newListing.phone)" placeholder="+1 800-000-0000" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" (click)="prevStep()">Back</button>
|
<button type="button" (click)="prevStep()">Back</button>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Title } from '@angular/platform-browser';
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Authentication } from 'app/services/Authentication';
|
import { Authentication } from 'app/services/Authentication';
|
||||||
import { Company } from 'app/models/Company';
|
import { Company } from 'app/models/Company';
|
||||||
|
import { Validation } from 'app/services/Validation';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'main-company-editor',
|
selector: 'main-company-editor',
|
||||||
@@ -23,7 +24,7 @@ export class CompanyEditorComponent {
|
|||||||
public ErrorMsg: string = "";
|
public ErrorMsg: string = "";
|
||||||
MaxFileMB: number = 3;
|
MaxFileMB: number = 3;
|
||||||
|
|
||||||
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, public validator: Validation ) {
|
||||||
this.title.setTitle("Company - Editor | BoredCareers");
|
this.title.setTitle("Company - Editor | BoredCareers");
|
||||||
if (!auth.isLoggedIn){
|
if (!auth.isLoggedIn){
|
||||||
router.navigate(["/"]);
|
router.navigate(["/"]);
|
||||||
@@ -54,6 +55,18 @@ export class CompanyEditorComponent {
|
|||||||
this.updateUI(0);
|
this.updateUI(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validatePhone(input: string){
|
||||||
|
let result = this.validator.validatePhoneNumber(input);
|
||||||
|
this.newListing.phone = result[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
validateEmail(input: string){
|
||||||
|
let result = this.validator.validateEmail(input);
|
||||||
|
if (result[0]){
|
||||||
|
this.newListing.email = result[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('window:keydown', ['$event'])
|
@HostListener('window:keydown', ['$event'])
|
||||||
handleGlobalKeyDown(event: KeyboardEvent){
|
handleGlobalKeyDown(event: KeyboardEvent){
|
||||||
if ( event.key === 'Tab' ){
|
if ( event.key === 'Tab' ){
|
||||||
@@ -122,51 +135,73 @@ export class CompanyEditorComponent {
|
|||||||
PostNewCompany(company: Company){
|
PostNewCompany(company: Company){
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.name)){
|
if (this.isNullOrEmpty(company.name)){
|
||||||
|
this.ErrorMsg = "Comany name is blank";
|
||||||
this.focusFrame(0, 0);
|
this.focusFrame(0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.websiteURL)){
|
if (this.isNullOrEmpty(company.websiteURL)){
|
||||||
|
this.ErrorMsg = "Website URL is blank";
|
||||||
this.focusFrame(1, 0);
|
this.focusFrame(1, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.logo)){
|
if (this.isNullOrEmpty(company.logo)){
|
||||||
|
this.ErrorMsg = "Logo is blank";
|
||||||
this.focusFrame(2, 0);
|
this.focusFrame(2, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.email)){
|
if (this.isNullOrEmpty(company.email)){
|
||||||
|
this.ErrorMsg = "Email is blank";
|
||||||
|
this.focusFrame(3, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.validator.validateEmail(company.email)[0]){
|
||||||
|
this.ErrorMsg = "Email is invalid";
|
||||||
this.focusFrame(3, 0);
|
this.focusFrame(3, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.phone)){
|
if (this.isNullOrEmpty(company.phone)){
|
||||||
|
this.ErrorMsg = "Phone number is blank";
|
||||||
|
this.focusFrame(3, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.validator.validatePhoneNumber(company.phone)[0]){
|
||||||
|
this.ErrorMsg = "Phone number is invalid";
|
||||||
this.focusFrame(3, 1);
|
this.focusFrame(3, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.city)){
|
if (this.isNullOrEmpty(company.city)){
|
||||||
|
this.ErrorMsg = "City is blank";
|
||||||
this.focusFrame(4, 0);
|
this.focusFrame(4, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.country)){
|
if (this.isNullOrEmpty(company.country)){
|
||||||
|
this.ErrorMsg = "Country is blank";
|
||||||
this.focusFrame(4, 1);
|
this.focusFrame(4, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.stateOrRegion)){
|
if (this.isNullOrEmpty(company.stateOrRegion)){
|
||||||
|
this.ErrorMsg = "State or Region is blank";
|
||||||
this.focusFrame(4, 2);
|
this.focusFrame(4, 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.postalCode)){
|
if (this.isNullOrEmpty(company.postalCode)){
|
||||||
|
this.ErrorMsg = "Postal Code is blank";
|
||||||
this.focusFrame(4, 3);
|
this.focusFrame(4, 3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isNullOrEmpty(company.description)){
|
if (this.isNullOrEmpty(company.description)){
|
||||||
|
this.ErrorMsg = "Description is blank";
|
||||||
this.focusFrame(5, 0);
|
this.focusFrame(5, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Skills -->
|
||||||
|
<div #step class="sub-frame">
|
||||||
|
<div class="center">
|
||||||
|
<div class="content-frame">
|
||||||
|
<label>Skills</label>
|
||||||
|
<button type="button" (click)="addSkill()">+</button>
|
||||||
|
</div>
|
||||||
|
@for(skill of Listing.skills; track skill.trackUUID){
|
||||||
|
<div class="content-frame">
|
||||||
|
<input [name]="'skillname' + skill.trackUUID" [(ngModel)]="skill.name" type="text" />
|
||||||
|
<textarea [name]="'skilldescription' + skill.trackUUID" [(ngModel)]="skill.description" type="text"></textarea>
|
||||||
|
<button type="button" (click)="remSkill(skill)">-</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="content-frame">
|
||||||
|
<button type="button" (click)="prevStep()">Back</button>
|
||||||
|
<button type="button" (click)="nextStep()">Next</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Description -->
|
<!-- Description -->
|
||||||
<div #step class="sub-frame">
|
<div #step class="sub-frame">
|
||||||
<div class="center">
|
<div class="center">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms';
|
|||||||
import { Router, ActivatedRoute, RouterModule } from '@angular/router';
|
import { Router, ActivatedRoute, RouterModule } from '@angular/router';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { JobListing } from 'app/models/JobListing';
|
import { JobListing, JobListingSkills } from 'app/models/JobListing';
|
||||||
import { Authentication } from 'app/services/Authentication';
|
import { Authentication } from 'app/services/Authentication';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -51,6 +51,9 @@ export class JobEditorComponent {
|
|||||||
if (this.mode === "edit") {
|
if (this.mode === "edit") {
|
||||||
this.http.get<JobListing>("api/joblisting/" + JobID).subscribe({
|
this.http.get<JobListing>("api/joblisting/" + JobID).subscribe({
|
||||||
next: data => {
|
next: data => {
|
||||||
|
data.skills.forEach(element => {
|
||||||
|
element.trackUUID = crypto.randomUUID();
|
||||||
|
});
|
||||||
this.Listing = data;
|
this.Listing = data;
|
||||||
},
|
},
|
||||||
error: err => {
|
error: err => {
|
||||||
@@ -80,6 +83,20 @@ export class JobEditorComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addSkill(){
|
||||||
|
this.Listing.skills.push(new JobListingSkills);
|
||||||
|
}
|
||||||
|
|
||||||
|
remSkill(self: JobListingSkills){
|
||||||
|
for(let i=0; i<this.Listing.skills.length; i++){
|
||||||
|
let cur = this.Listing.skills[i];
|
||||||
|
if (cur.trackUUID === self.trackUUID){
|
||||||
|
this.Listing.skills.splice( i, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nextStep(){
|
nextStep(){
|
||||||
this.currentStep += 1;
|
this.currentStep += 1;
|
||||||
this.updateUI();
|
this.updateUI();
|
||||||
|
|||||||
@@ -47,7 +47,24 @@
|
|||||||
<h1>{{ selectedJob.country }}</h1>
|
<h1>{{ selectedJob.country }}</h1>
|
||||||
<h1>{{ selectedJob.postalCode }}</h1>
|
<h1>{{ selectedJob.postalCode }}</h1>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Required Skills</h1>
|
||||||
|
@for(skill of selectedJob.skills; track skill.trackUUID){
|
||||||
|
<div>
|
||||||
|
<h1>{{ skill.name }}</h1>
|
||||||
|
<h1>{{ skill.description }}</h1>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<h1>{{ selectedJob.description }}</h1>
|
<h1>{{ selectedJob.description }}</h1>
|
||||||
|
<div>
|
||||||
|
@for(resume of myResumes; track resume.trackUUID){
|
||||||
|
<div>
|
||||||
|
<button type="button" (click)="applyWithResume(resume)">APPLY USING RESUME: {{ resume.name }}</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -7,6 +7,8 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { Authentication } from 'app/services/Authentication';
|
import { Authentication } from 'app/services/Authentication';
|
||||||
import { JobListing } from 'app/models/JobListing';
|
import { JobListing } from 'app/models/JobListing';
|
||||||
import { Company } from 'app/models/Company';
|
import { Company } from 'app/models/Company';
|
||||||
|
import { Resume } from 'app/models/Resume';
|
||||||
|
import { Application } from 'app/models/Application';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'main-jobs-viewer',
|
selector: 'main-jobs-viewer',
|
||||||
@@ -17,9 +19,12 @@ import { Company } from 'app/models/Company';
|
|||||||
export class JobViewerComponent {
|
export class JobViewerComponent {
|
||||||
|
|
||||||
public selectedJob: JobListing | null = null;
|
public selectedJob: JobListing | null = null;
|
||||||
|
public myResumes: Resume[] = [];
|
||||||
public jobsCompany: Company | null = null;
|
public jobsCompany: Company | null = null;
|
||||||
public ErrorMsg: string = "";
|
public ErrorMsg: string = "";
|
||||||
|
|
||||||
|
JobListingID: number = -1;
|
||||||
|
|
||||||
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");
|
||||||
};
|
};
|
||||||
@@ -27,7 +32,8 @@ export class JobViewerComponent {
|
|||||||
ngOnInit(){
|
ngOnInit(){
|
||||||
this.route.queryParams.subscribe(params => {
|
this.route.queryParams.subscribe(params => {
|
||||||
const JobID = params['JobID'];
|
const JobID = params['JobID'];
|
||||||
if (JobID){
|
if (JobID) {
|
||||||
|
this.JobListingID = JobID;
|
||||||
this.http.get<JobListing>( "api/joblisting/" + JobID ).subscribe({
|
this.http.get<JobListing>( "api/joblisting/" + JobID ).subscribe({
|
||||||
next: data => {
|
next: data => {
|
||||||
this.selectedJob = data;
|
this.selectedJob = data;
|
||||||
@@ -51,6 +57,41 @@ export class JobViewerComponent {
|
|||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.http.get<Resume[]>("api/resume").subscribe({
|
||||||
|
next: data => {
|
||||||
|
this.myResumes = data;
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
console.log("Error fetching resumes: " + err.error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
applyWithResume(resume: Resume) {
|
||||||
|
var application = new Application;
|
||||||
|
|
||||||
|
if (this.auth.loggedInUser.id != null){
|
||||||
|
application.accountID = this.auth.loggedInUser.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resume.id != null){
|
||||||
|
application.resumeID = resume.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
application.jobListingID = this.JobListingID;
|
||||||
|
application.hasBeenViewed = false;
|
||||||
|
application.responseEmail = resume.email;
|
||||||
|
|
||||||
|
this.http.post("api/application", application).subscribe({
|
||||||
|
next: data => {
|
||||||
|
this.router.navigate(["/"]);
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
this.ErrorMsg = err.error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<input [name]="'resumeemail' + resume.trackUUID" [(ngModel)]="resume.email" type="email" placeholder="Email Address" />
|
<input [name]="'resumeemail' + resume.trackUUID" [(ngModel)]="resume.email" type="email" (ngModelChange)="validateEmail(resume.email)" placeholder="Email Address" />
|
||||||
<input [name]="'resumephoneNumber' + resume.trackUUID" [(ngModel)]="resume.phoneNumber" type="tel" placeholder="Phone number" />
|
<input [name]="'resumephoneNumber' + resume.trackUUID" [(ngModel)]="resume.phoneNumber" (ngModelChange)="validatePhone(resume.phoneNumber)" type="tel" placeholder="Phone number" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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 { Validation } from 'app/services/Validation';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'main-resume-editor',
|
selector: 'main-resume-editor',
|
||||||
@@ -20,7 +21,7 @@ export class ResumesEditorComponent {
|
|||||||
|
|
||||||
public ErrorMsg: string = "";
|
public ErrorMsg: string = "";
|
||||||
|
|
||||||
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, public validator: Validation ) {
|
||||||
this.title.setTitle("Resume - Editor | BoredCareers");
|
this.title.setTitle("Resume - Editor | BoredCareers");
|
||||||
if (!this.auth.isLoggedIn){
|
if (!this.auth.isLoggedIn){
|
||||||
this.router.navigate(["/"]);
|
this.router.navigate(["/"]);
|
||||||
@@ -75,11 +76,6 @@ export class ResumesEditorComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagnation //
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
SubmitForm(resume: Resume){
|
SubmitForm(resume: Resume){
|
||||||
resume.accountID = this.auth.loggedInUser.id;
|
resume.accountID = this.auth.loggedInUser.id;
|
||||||
this.http.post("api/resume", resume).subscribe({
|
this.http.post("api/resume", resume).subscribe({
|
||||||
@@ -92,6 +88,20 @@ export class ResumesEditorComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validatePhone(input: string){
|
||||||
|
let result = this.validator.validatePhoneNumber(input);
|
||||||
|
if (result[0]){
|
||||||
|
this.resume.phoneNumber = result[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateEmail(input: string){
|
||||||
|
let result = this.validator.validateEmail(input);
|
||||||
|
if (result[0]){
|
||||||
|
this.resume.email = result[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PrintResume(){
|
PrintResume(){
|
||||||
const divToPrint = document.getElementsByClassName("paper")[0];
|
const divToPrint = document.getElementsByClassName("paper")[0];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
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 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-sub-section {
|
||||||
|
border: 1px solid #666666;
|
||||||
|
break-inside: avoid;
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,301 @@
|
|||||||
|
|
||||||
|
<div class="resume-header">
|
||||||
|
<div>
|
||||||
|
<input [name]="'resumetitle' + resume.trackUUID" [(ngModel)]="resume.title" type="text" placeholder="Resume Name" />
|
||||||
|
</div>
|
||||||
|
<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" />
|
||||||
|
</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 -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Experience</h1>
|
||||||
|
@for(experience of resume.experiences; track experience.trackUUID ){
|
||||||
|
<div class="resume-sub-section">
|
||||||
|
<input [name]="'experiencejobTitle' + experience.trackUUID" [(ngModel)]="experience.jobTitle" type="text" placeholder="Job Title" />
|
||||||
|
<input [name]="'experiencecompany' + experience.trackUUID" [(ngModel)]="experience.company" type="text" placeholder="Company" />
|
||||||
|
<input [name]="'experiencecity' + experience.trackUUID" [(ngModel)]="experience.city" type="text" placeholder="City" />
|
||||||
|
<input [name]="'experiencestateOrRegion' + experience.trackUUID" [(ngModel)]="experience.stateOrRegion" type="text" placeholder="State" />
|
||||||
|
<input [name]="'experiencecountry' + experience.trackUUID" [(ngModel)]="experience.country" type="text" placeholder="Country" />
|
||||||
|
<input [name]="'experiencepostalCode' + experience.trackUUID" [(ngModel)]="experience.postalCode" type="text" placeholder="Postal Code" />
|
||||||
|
<input [name]="'experiencestillEmployed' + experience.trackUUID" [(ngModel)]="experience.stillEmployed" type="checkbox" />
|
||||||
|
<input [name]="'experiencedateStarted' + experience.trackUUID" [(ngModel)]="experience.dateStarted" type="date" />
|
||||||
|
@if(!experience.stillEmployed){
|
||||||
|
<input [name]="'experiencedateEnded' + experience.trackUUID" [(ngModel)]="experience.dateEnded" type="date" />
|
||||||
|
}
|
||||||
|
@for(bullet of experience.experienceBullets; track bullet.trackUUID){
|
||||||
|
<div>
|
||||||
|
<textarea [name]="'bulletjobFunction' + bullet.trackUUID" [(ngModel)]="bullet.jobFunction" placeholder="Job Task / Function" ></textarea>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Military -->
|
||||||
|
@if(resume.military !== null){
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Military</h1>
|
||||||
|
<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" />
|
||||||
|
<input [name]="'militarydateStarted' + resume.military.trackUUID" [(ngModel)]="resume.military.dateStarted" type="date" />
|
||||||
|
@if (!resume.military.stillServing){
|
||||||
|
<input [name]="'dateEnded' + resume.military.trackUUID" [(ngModel)]="resume.military.dateEnded" type="date" />
|
||||||
|
}
|
||||||
|
@for(military of resume.military.militaryBullets; track military.trackUUID ){
|
||||||
|
<div class="resume-sub-section">
|
||||||
|
<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>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Education -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Education</h1>
|
||||||
|
@for(education of resume.educations; track education.trackUUID){
|
||||||
|
<div class="resume-sub-section">
|
||||||
|
<input [name]="'educationschool' + education.trackUUID" [(ngModel)]="education.school" type="text" placeholder="School" />
|
||||||
|
<input [name]="'educationdegreeType' + education.trackUUID" [(ngModel)]="education.degreeType" type="text" placeholder="Type" />
|
||||||
|
<input [name]="'educationdegreeField' + education.trackUUID" [(ngModel)]="education.degreeField" type="text" placeholder="Field" />
|
||||||
|
<input [name]="'educationcity' + education.trackUUID" [(ngModel)]="education.city" type="text" placeholder="City" />
|
||||||
|
<input [name]="'educationstateOrRegion' + education.trackUUID" [(ngModel)]="education.stateOrRegion" type="text" placeholder="State" />
|
||||||
|
<input [name]="'educationcountry' + education.trackUUID" [(ngModel)]="education.country" type="text" placeholder="Country" />
|
||||||
|
<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]="'educationdateStarted' + education.trackUUID" [(ngModel)]="education.dateStarted" type="date" />
|
||||||
|
@if (!education.stillStudying){
|
||||||
|
<input [name]="'educationdateEnded' + education.trackUUID" [(ngModel)]="education.dateEnded" type="date" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="resume-header">
|
||||||
|
<div>
|
||||||
|
<input [name]="'resumetitle' + resume.trackUUID" [(ngModel)]="resume.title" type="text" placeholder="Resume Name" />
|
||||||
|
</div>
|
||||||
|
<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" />
|
||||||
|
</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 -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Experience</h1>
|
||||||
|
@for(experience of resume.experiences; track experience.trackUUID ){
|
||||||
|
<div class="resume-sub-section">
|
||||||
|
<input [name]="'experiencejobTitle' + experience.trackUUID" [(ngModel)]="experience.jobTitle" type="text" placeholder="Job Title" />
|
||||||
|
<input [name]="'experiencecompany' + experience.trackUUID" [(ngModel)]="experience.company" type="text" placeholder="Company" />
|
||||||
|
<input [name]="'experiencecity' + experience.trackUUID" [(ngModel)]="experience.city" type="text" placeholder="City" />
|
||||||
|
<input [name]="'experiencestateOrRegion' + experience.trackUUID" [(ngModel)]="experience.stateOrRegion" type="text" placeholder="State" />
|
||||||
|
<input [name]="'experiencecountry' + experience.trackUUID" [(ngModel)]="experience.country" type="text" placeholder="Country" />
|
||||||
|
<input [name]="'experiencepostalCode' + experience.trackUUID" [(ngModel)]="experience.postalCode" type="text" placeholder="Postal Code" />
|
||||||
|
<input [name]="'experiencestillEmployed' + experience.trackUUID" [(ngModel)]="experience.stillEmployed" type="checkbox" />
|
||||||
|
<input [name]="'experiencedateStarted' + experience.trackUUID" [(ngModel)]="experience.dateStarted" type="date" />
|
||||||
|
@if(!experience.stillEmployed){
|
||||||
|
<input [name]="'experiencedateEnded' + experience.trackUUID" [(ngModel)]="experience.dateEnded" type="date" />
|
||||||
|
}
|
||||||
|
@for(bullet of experience.experienceBullets; track bullet.trackUUID){
|
||||||
|
<div>
|
||||||
|
<textarea [name]="'bulletjobFunction' + bullet.trackUUID" [(ngModel)]="bullet.jobFunction" placeholder="Job Task / Function" ></textarea>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Military -->
|
||||||
|
@if(resume.military !== null){
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Military</h1>
|
||||||
|
<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" />
|
||||||
|
<input [name]="'militarydateStarted' + resume.military.trackUUID" [(ngModel)]="resume.military.dateStarted" type="date" />
|
||||||
|
@if (!resume.military.stillServing){
|
||||||
|
<input [name]="'dateEnded' + resume.military.trackUUID" [(ngModel)]="resume.military.dateEnded" type="date" />
|
||||||
|
}
|
||||||
|
@for(military of resume.military.militaryBullets; track military.trackUUID ){
|
||||||
|
<div class="resume-sub-section">
|
||||||
|
<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>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Education -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Education</h1>
|
||||||
|
@for(education of resume.educations; track education.trackUUID){
|
||||||
|
<div class="resume-sub-section">
|
||||||
|
<input [name]="'educationschool' + education.trackUUID" [(ngModel)]="education.school" type="text" placeholder="School" />
|
||||||
|
<input [name]="'educationdegreeType' + education.trackUUID" [(ngModel)]="education.degreeType" type="text" placeholder="Type" />
|
||||||
|
<input [name]="'educationdegreeField' + education.trackUUID" [(ngModel)]="education.degreeField" type="text" placeholder="Field" />
|
||||||
|
<input [name]="'educationcity' + education.trackUUID" [(ngModel)]="education.city" type="text" placeholder="City" />
|
||||||
|
<input [name]="'educationstateOrRegion' + education.trackUUID" [(ngModel)]="education.stateOrRegion" type="text" placeholder="State" />
|
||||||
|
<input [name]="'educationcountry' + education.trackUUID" [(ngModel)]="education.country" type="text" placeholder="Country" />
|
||||||
|
<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]="'educationdateStarted' + education.trackUUID" [(ngModel)]="education.dateStarted" type="date" />
|
||||||
|
@if (!education.stillStudying){
|
||||||
|
<input [name]="'educationdateEnded' + education.trackUUID" [(ngModel)]="education.dateEnded" type="date" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Skill -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Skills</h1>
|
||||||
|
@for(skill of resume.skills; track skill.trackUUID){
|
||||||
|
<div class="resume-sub-section flex-two-row">
|
||||||
|
<div>
|
||||||
|
<input [name]="'skillname' + skill.trackUUID" [(ngModel)]="skill.name" type="text" placeholder="Skill" />
|
||||||
|
</div>
|
||||||
|
<textarea [name]="'skilldescription' + skill.trackUUID" [(ngModel)]="skill.description" placeholder="Description"></textarea>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Language -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Languages</h1>
|
||||||
|
@for(language of resume.languages; track language.trackUUID){
|
||||||
|
<div class="resume-sub-section flex-two-row">
|
||||||
|
<input [name]="'languagelanguage' + language.trackUUID" [(ngModel)]="language.language" type="text" placeholder="Language" />
|
||||||
|
<input [name]="'languageproficiency' + language.trackUUID" [(ngModel)]="language.proficiency" type="text" placeholder="Proficiency" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Certification -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Certifications</h1>
|
||||||
|
@for(cert of resume.certifications; track cert.trackUUID){
|
||||||
|
<div class="resume-sub-section flex-two-row">
|
||||||
|
<div>
|
||||||
|
<input [name]="'certname' + cert.trackUUID" [(ngModel)]="cert.name" type="text" placeholder="Certification Name" />
|
||||||
|
<input [name]="'certverificationURL' + cert.trackUUID" [(ngModel)]="cert.verificationURL" type="text" placeholder="Verification URL" />
|
||||||
|
</div>
|
||||||
|
<textarea [name]="'certdescription' + cert.trackUUID" [(ngModel)]="cert.description" placeholder="Description"></textarea>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Project -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Projects</h1>
|
||||||
|
@for(proj of resume.projects; track proj.trackUUID){
|
||||||
|
<div class="resume-sub-section flex-two-row">
|
||||||
|
<div>
|
||||||
|
<input [name]="'projname' + proj.trackUUID" [(ngModel)]="proj.name" type="text" placeholder="Project Name" />
|
||||||
|
<input [name]="'projurl' + proj.trackUUID" [(ngModel)]="proj.url" type="text" placeholder="Reference URL" />
|
||||||
|
</div>
|
||||||
|
<textarea [name]="'projdescription' + proj.trackUUID" [(ngModel)]="proj.description" placeholder="Description"></textarea>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Skill -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Skills</h1>
|
||||||
|
@for(skill of resume.skills; track skill.trackUUID){
|
||||||
|
<div class="resume-sub-section flex-two-row">
|
||||||
|
<div>
|
||||||
|
<input [name]="'skillname' + skill.trackUUID" [(ngModel)]="skill.name" type="text" placeholder="Skill" />
|
||||||
|
</div>
|
||||||
|
<textarea [name]="'skilldescription' + skill.trackUUID" [(ngModel)]="skill.description" placeholder="Description"></textarea>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Language -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Languages</h1>
|
||||||
|
@for(language of resume.languages; track language.trackUUID){
|
||||||
|
<div class="resume-sub-section flex-two-row">
|
||||||
|
<input [name]="'languagelanguage' + language.trackUUID" [(ngModel)]="language.language" type="text" placeholder="Language" />
|
||||||
|
<input [name]="'languageproficiency' + language.trackUUID" [(ngModel)]="language.proficiency" type="text" placeholder="Proficiency" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Certification -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Certifications</h1>
|
||||||
|
@for(cert of resume.certifications; track cert.trackUUID){
|
||||||
|
<div class="resume-sub-section flex-two-row">
|
||||||
|
<div>
|
||||||
|
<input [name]="'certname' + cert.trackUUID" [(ngModel)]="cert.name" type="text" placeholder="Certification Name" />
|
||||||
|
<input [name]="'certverificationURL' + cert.trackUUID" [(ngModel)]="cert.verificationURL" type="text" placeholder="Verification URL" />
|
||||||
|
</div>
|
||||||
|
<textarea [name]="'certdescription' + cert.trackUUID" [(ngModel)]="cert.description" placeholder="Description"></textarea>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Project -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1 class="title-text">Projects</h1>
|
||||||
|
@for(proj of resume.projects; track proj.trackUUID){
|
||||||
|
<div class="resume-sub-section flex-two-row">
|
||||||
|
<div>
|
||||||
|
<input [name]="'projname' + proj.trackUUID" [(ngModel)]="proj.name" type="text" placeholder="Project Name" />
|
||||||
|
<input [name]="'projurl' + proj.trackUUID" [(ngModel)]="proj.url" type="text" placeholder="Reference URL" />
|
||||||
|
</div>
|
||||||
|
<textarea [name]="'projdescription' + proj.trackUUID" [(ngModel)]="proj.description" placeholder="Description"></textarea>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { Router, ActivatedRoute, RouterModule } from '@angular/router';
|
||||||
|
import { Title } from '@angular/platform-browser';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Resume } from 'app/models/Resume';
|
||||||
|
import { Authentication } from 'app/services/Authentication';
|
||||||
|
import { Validation } from 'app/services/Validation';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'main-resume-viewer',
|
||||||
|
templateUrl: './viewer.component.html',
|
||||||
|
styleUrls: [ './viewer.component.css' ],
|
||||||
|
imports: [FormsModule, CommonModule, RouterModule]
|
||||||
|
})
|
||||||
|
export class ResumesViewerComponent {
|
||||||
|
|
||||||
|
public resume: Resume = new Resume;
|
||||||
|
|
||||||
|
public ErrorMsg: string = "";
|
||||||
|
|
||||||
|
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication, public validator: Validation ) {
|
||||||
|
this.title.setTitle("Resume - Viewer | BoredCareers");
|
||||||
|
if (!this.auth.isLoggedIn){
|
||||||
|
this.router.navigate(["/"]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ngOnInit(){
|
||||||
|
this.route.queryParams.subscribe(params => {
|
||||||
|
const ResumeID = params['ResumeID'] ? +params['ResumeID'] : null;
|
||||||
|
if (ResumeID !== null){
|
||||||
|
this.http.get<Resume>("api/resume?ResumeID=" + ResumeID).subscribe({
|
||||||
|
next: data => {
|
||||||
|
|
||||||
|
data.trackUUID = crypto.randomUUID();
|
||||||
|
data.certifications.forEach(element => {
|
||||||
|
element.trackUUID = crypto.randomUUID();
|
||||||
|
});
|
||||||
|
data.educations.forEach(element => {
|
||||||
|
element.trackUUID = crypto.randomUUID();
|
||||||
|
});
|
||||||
|
data.experiences.forEach(element => {
|
||||||
|
element.trackUUID = crypto.randomUUID();
|
||||||
|
element.experienceBullets.forEach(subelement => {
|
||||||
|
subelement.trackUUID = crypto.randomUUID();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
data.languages.forEach(element => {
|
||||||
|
element.trackUUID = crypto.randomUUID();
|
||||||
|
});
|
||||||
|
if (data.military){
|
||||||
|
data.military.trackUUID = crypto.randomUUID();
|
||||||
|
data.military.militaryBullets.forEach(element => {
|
||||||
|
element.trackUUID = crypto.randomUUID();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
data.projects.forEach(element => {
|
||||||
|
element.trackUUID = crypto.randomUUID();
|
||||||
|
});
|
||||||
|
data.skills.forEach(element => {
|
||||||
|
element.trackUUID = crypto.randomUUID();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resume = data;
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
this.ErrorMsg = err.error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class Validation {
|
||||||
|
|
||||||
|
constructor(){ }
|
||||||
|
|
||||||
|
validatePhoneNumber(input: string): [boolean, string] {
|
||||||
|
var sanitized = input.replace(/\D/g, '');
|
||||||
|
if (sanitized.length < 10){
|
||||||
|
let formatted = sanitized.replace(/(\d{3})(?=\d{3})/g, '$1-').replace(/(\d{4})(?=\d{1,4}$)/, '$1-');
|
||||||
|
return [false, formatted];
|
||||||
|
} else if (sanitized.length === 10) {
|
||||||
|
let result = `(${sanitized.slice(0, 3)})${sanitized.slice(3, 6)}-${sanitized.slice(6, 10)}`;
|
||||||
|
return [true, result];
|
||||||
|
} else if (sanitized.length > 10 && sanitized.length < 14) {
|
||||||
|
let countryCode = sanitized.slice(0, sanitized.length - 10);
|
||||||
|
let areaCode = sanitized.slice(sanitized.length - 10, sanitized.length - 7);
|
||||||
|
let firstPart = sanitized.slice(sanitized.length - 7, sanitized.length - 4);
|
||||||
|
let secondPart = sanitized.slice(sanitized.length - 4);
|
||||||
|
let result = `+${countryCode} (${areaCode})${firstPart}-${secondPart}`;
|
||||||
|
return [true, result];
|
||||||
|
}else{
|
||||||
|
return [false, input];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
|
||||||
|
validateEmail(input: string): [boolean, string] {
|
||||||
|
const corrected = input.trim().toLowerCase();
|
||||||
|
const success = this.emailRegex.test(corrected);
|
||||||
|
return [success, corrected];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,13 +10,19 @@ namespace BoredCareers.Controllers {
|
|||||||
public ApplicationController(DatabaseService db) : base(db) {}
|
public ApplicationController(DatabaseService db) : base(db) {}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GetApplication(int ApplicationID) {
|
public async Task<IActionResult> GetApplication(int? ApplicationID, int? JobListingID) {
|
||||||
if (isLoggedIn()) {
|
if (isLoggedIn()) {
|
||||||
Application? application = await _databaseService.GetApplication(ApplicationID);
|
if (ApplicationID != null) {
|
||||||
if (application != null) {
|
Application? application = await _databaseService.GetApplication(Convert.ToInt32(ApplicationID));
|
||||||
return Ok(application);
|
if (application != null) {
|
||||||
|
return Ok(application);
|
||||||
|
}
|
||||||
|
return NotFound("Application doesn't exist");
|
||||||
|
} else if (JobListingID != null) {
|
||||||
|
Application[] applications = await _databaseService.GetApplicationsFromJobListing(Convert.ToInt32(JobListingID));
|
||||||
|
return Ok(applications);
|
||||||
}
|
}
|
||||||
return NotFound("Application doesn't exist");
|
return NotFound("No query selector supplied");
|
||||||
}
|
}
|
||||||
return NotFound("Not logged in");
|
return NotFound("Not logged in");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,6 +228,8 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
Description = @Description,
|
Description = @Description,
|
||||||
ModifiedTime = @ModifiedTime,
|
ModifiedTime = @ModifiedTime,
|
||||||
IsDeleted = @IsDeleted;
|
IsDeleted = @IsDeleted;
|
||||||
|
|
||||||
|
SELECT LAST_INSERT_ID();
|
||||||
";
|
";
|
||||||
|
|
||||||
MySqlCommand cmd = new MySqlCommand(command, connection);
|
MySqlCommand cmd = new MySqlCommand(command, connection);
|
||||||
@@ -247,9 +249,17 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
cmd.Parameters.AddWithValue("@ModifiedTime", DateTime.UtcNow);
|
cmd.Parameters.AddWithValue("@ModifiedTime", DateTime.UtcNow);
|
||||||
cmd.Parameters.AddWithValue("@IsDeleted", jobListing.IsDeleted);
|
cmd.Parameters.AddWithValue("@IsDeleted", jobListing.IsDeleted);
|
||||||
|
|
||||||
await cmd.ExecuteNonQueryAsync();
|
object? result = await cmd.ExecuteScalarAsync();
|
||||||
|
int jobListingID = 0;
|
||||||
|
if (jobListing.ID != null && jobListing.ID != 0) {
|
||||||
|
jobListingID = Convert.ToInt32(jobListing.ID);
|
||||||
|
} else {
|
||||||
|
cmd.CommandText = "";
|
||||||
|
jobListingID = Convert.ToInt32(result);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (JobListingSkill cur in jobListing.Skills) {
|
foreach (JobListingSkill cur in jobListing.Skills) {
|
||||||
|
cur.JobListingID = jobListingID;
|
||||||
await SetJobListingSkills(cur);
|
await SetJobListingSkills(cur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
using( MySqlConnection connection = GetConnection() ) {
|
using( MySqlConnection connection = GetConnection() ) {
|
||||||
await connection.OpenAsync();
|
await connection.OpenAsync();
|
||||||
string command = @"
|
string command = @"
|
||||||
INSERT INTO JobListing
|
INSERT INTO JobListingSkill
|
||||||
(ID,JobListingID,Name,Description)
|
(ID,JobListingID,Name,Description)
|
||||||
VALUES
|
VALUES
|
||||||
(@ID,@JobListingID,@Name,@Description)
|
(@ID,@JobListingID,@Name,@Description)
|
||||||
|
|||||||
Reference in New Issue
Block a user