adding skills to experiences, profiles, and projects
This commit is contained in:
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,2 +1,9 @@
|
|||||||
|
.vscode/*
|
||||||
|
node_modules
|
||||||
|
**/.env
|
||||||
|
**/.env.*
|
||||||
|
**/*.env
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.auto.tfvars
|
.dapr
|
||||||
|
**/**/secrets.json
|
||||||
|
.prod
|
||||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
FROM node:24
|
||||||
|
|
||||||
|
WORKDIR app
|
||||||
|
COPY ./api/dist ./api/dist
|
||||||
|
COPY ./api/package.json package-lock.json ./api
|
||||||
|
COPY ./client/dist ./client/dist
|
||||||
|
|
||||||
|
WORKDIR api
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
WORKDIR /
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node", "./app/api/dist/main.js"]
|
||||||
|
# ENTRYPOINT ["tail", "-f", "/dev/null"]
|
||||||
@@ -6,5 +6,11 @@ export default () => ({
|
|||||||
clientSecret: process.env.CLIENT_SECRET,
|
clientSecret: process.env.CLIENT_SECRET,
|
||||||
issuer: process.env.ISSUER_URL,
|
issuer: process.env.ISSUER_URL,
|
||||||
jwksUri: process.env.JWKS_URI,
|
jwksUri: process.env.JWKS_URI,
|
||||||
tenantId: process.env.TENANT_ID
|
tenantId: process.env.TENANT_ID,
|
||||||
|
db: {
|
||||||
|
sync: process.env.DB_SYNC,
|
||||||
|
migrationsRun: process.env.DB_MIGRATIONS_RUN,
|
||||||
|
path: process.env.DB_PATH
|
||||||
|
},
|
||||||
|
dbPath: process.env.DB_PATH
|
||||||
})
|
})
|
||||||
@@ -12,7 +12,7 @@ export const dataSourceOptions: DataSourceOptions & SeederOptions = {
|
|||||||
database: configService.get<string>('DB_PATH'),
|
database: configService.get<string>('DB_PATH'),
|
||||||
entities: ['../**/*.entity.js'],
|
entities: ['../**/*.entity.js'],
|
||||||
migrations: ['dist/database/migrations/**/*.js'],
|
migrations: ['dist/database/migrations/**/*.js'],
|
||||||
migrationsRun: false,
|
migrationsRun: configService.get<boolean>('DB_MIGRATIONS_RUN'),
|
||||||
seeds: ['dist/database/seeds/**/*.ts'],
|
seeds: ['dist/database/seeds/**/*.ts'],
|
||||||
synchronize: configService.get<boolean>('DB_SYNC')
|
synchronize: configService.get<boolean>('DB_SYNC')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,122 @@
|
|||||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
export class InitialMigration1782738482901 implements MigrationInterface {
|
export class InitialMigration1784577734670 implements MigrationInterface {
|
||||||
name = 'InitialMigration1782738482901'
|
name = 'InitialMigration1784577734670'
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`CREATE TABLE "statuses" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL)`);
|
await queryRunner.query(`CREATE TABLE "statuses" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL)`);
|
||||||
await queryRunner.query(`CREATE TABLE "skill_categories" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
await queryRunner.query(`CREATE TABLE "skill_categories" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
await queryRunner.query(`CREATE TABLE "skill_levels" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
await queryRunner.query(`CREATE TABLE "skill_levels" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
await queryRunner.query(`CREATE TABLE "skill_ranks" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "weight" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
await queryRunner.query(`CREATE TABLE "skill_ranks" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "weight" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
await queryRunner.query(`CREATE TABLE "skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_168133e3158020b53392549d3e" UNIQUE ("rankId"))`);
|
await queryRunner.query(`CREATE TABLE "profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
await queryRunner.query(`CREATE TABLE "projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_5a833dfa646b99b852c67dd859" UNIQUE ("statusId"))`);
|
await queryRunner.query(`CREATE TABLE "experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
await queryRunner.query(`CREATE TABLE "experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_23dfcd8f2d1b6585b848f840d5" UNIQUE ("statusId"))`);
|
await queryRunner.query(`CREATE TABLE "skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
await queryRunner.query(`CREATE TABLE "profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_a0e37cd676d13d116f73d494ee" UNIQUE ("statusId"))`);
|
await queryRunner.query(`CREATE TABLE "projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_168133e3158020b53392549d3e" UNIQUE ("rankId"), CONSTRAINT "FK_06d267f85858229c10a01a08ad7" FOREIGN KEY ("categoryId") REFERENCES "skill_categories" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_168133e3158020b53392549d3ee" FOREIGN KEY ("rankId") REFERENCES "skill_ranks" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_cad5a64685c1be599c10bb7fc7b" FOREIGN KEY ("levelId") REFERENCES "skill_levels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE TABLE "profiles_skills_skills" ("profilesId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("profilesId", "skillsId"))`);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_skills"("id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "skills"`);
|
await queryRunner.query(`CREATE INDEX "IDX_8401800ec9c15b8f383ac8d9c0" ON "profiles_skills_skills" ("profilesId") `);
|
||||||
await queryRunner.query(`DROP TABLE "skills"`);
|
await queryRunner.query(`CREATE INDEX "IDX_36a9448df496235d81a7ceb089" ON "profiles_skills_skills" ("skillsId") `);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_skills" RENAME TO "skills"`);
|
await queryRunner.query(`CREATE TABLE "experiences_skills_skills" ("experiencesId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("experiencesId", "skillsId"))`);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_5a833dfa646b99b852c67dd859" UNIQUE ("statusId"), CONSTRAINT "FK_5a833dfa646b99b852c67dd8593" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE INDEX "IDX_54957c4ce34cebce0c6f152b87" ON "experiences_skills_skills" ("experiencesId") `);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_projects"("id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "projects"`);
|
await queryRunner.query(`CREATE INDEX "IDX_b39ff48a29419ea48077b619c4" ON "experiences_skills_skills" ("skillsId") `);
|
||||||
await queryRunner.query(`DROP TABLE "projects"`);
|
await queryRunner.query(`CREATE TABLE "projects_skills_skills" ("projectsId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("projectsId", "skillsId"))`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_projects" RENAME TO "projects"`);
|
await queryRunner.query(`CREATE INDEX "IDX_d8128e9b444108a09d81529ea0" ON "projects_skills_skills" ("projectsId") `);
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_23dfcd8f2d1b6585b848f840d5" UNIQUE ("statusId"), CONSTRAINT "FK_be01c61f0c549f2187b5c05c349" FOREIGN KEY ("profileId") REFERENCES "profiles" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_23dfcd8f2d1b6585b848f840d5e" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
await queryRunner.query(`CREATE INDEX "IDX_5291aa5a2295552d375007fefe" ON "projects_skills_skills" ("skillsId") `);
|
||||||
await queryRunner.query(`INSERT INTO "temporary_experiences"("id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "experiences"`);
|
await queryRunner.query(`CREATE TABLE "temporary_profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "FK_a0e37cd676d13d116f73d494ee6" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
await queryRunner.query(`DROP TABLE "experiences"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_experiences" RENAME TO "experiences"`);
|
|
||||||
await queryRunner.query(`CREATE TABLE "temporary_profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_a0e37cd676d13d116f73d494ee" UNIQUE ("statusId"), CONSTRAINT "FK_a0e37cd676d13d116f73d494ee6" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
|
||||||
await queryRunner.query(`INSERT INTO "temporary_profiles"("id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "profiles"`);
|
await queryRunner.query(`INSERT INTO "temporary_profiles"("id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "profiles"`);
|
||||||
await queryRunner.query(`DROP TABLE "profiles"`);
|
await queryRunner.query(`DROP TABLE "profiles"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_profiles" RENAME TO "profiles"`);
|
await queryRunner.query(`ALTER TABLE "temporary_profiles" RENAME TO "profiles"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "FK_23dfcd8f2d1b6585b848f840d5e" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_be01c61f0c549f2187b5c05c349" FOREIGN KEY ("profileId") REFERENCES "profiles" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_experiences"("id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "experiences"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "experiences"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_experiences" RENAME TO "experiences"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "FK_06d267f85858229c10a01a08ad7" FOREIGN KEY ("categoryId") REFERENCES "skill_categories" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_168133e3158020b53392549d3ee" FOREIGN KEY ("rankId") REFERENCES "skill_ranks" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_cad5a64685c1be599c10bb7fc7b" FOREIGN KEY ("levelId") REFERENCES "skill_levels" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_skills"("id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "skills"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "skills"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_skills" RENAME TO "skills"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "FK_5a833dfa646b99b852c67dd8593" FOREIGN KEY ("statusId") REFERENCES "statuses" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_projects"("id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "projects"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "projects"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_projects" RENAME TO "projects"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_8401800ec9c15b8f383ac8d9c0"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_36a9448df496235d81a7ceb089"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_profiles_skills_skills" ("profilesId" varchar NOT NULL, "skillsId" varchar NOT NULL, CONSTRAINT "FK_8401800ec9c15b8f383ac8d9c0d" FOREIGN KEY ("profilesId") REFERENCES "profiles" ("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "FK_36a9448df496235d81a7ceb089d" FOREIGN KEY ("skillsId") REFERENCES "skills" ("id") ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY ("profilesId", "skillsId"))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_profiles_skills_skills"("profilesId", "skillsId") SELECT "profilesId", "skillsId" FROM "profiles_skills_skills"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "profiles_skills_skills"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_profiles_skills_skills" RENAME TO "profiles_skills_skills"`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_8401800ec9c15b8f383ac8d9c0" ON "profiles_skills_skills" ("profilesId") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_36a9448df496235d81a7ceb089" ON "profiles_skills_skills" ("skillsId") `);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_54957c4ce34cebce0c6f152b87"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_b39ff48a29419ea48077b619c4"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_experiences_skills_skills" ("experiencesId" varchar NOT NULL, "skillsId" varchar NOT NULL, CONSTRAINT "FK_54957c4ce34cebce0c6f152b875" FOREIGN KEY ("experiencesId") REFERENCES "experiences" ("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "FK_b39ff48a29419ea48077b619c46" FOREIGN KEY ("skillsId") REFERENCES "skills" ("id") ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY ("experiencesId", "skillsId"))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_experiences_skills_skills"("experiencesId", "skillsId") SELECT "experiencesId", "skillsId" FROM "experiences_skills_skills"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "experiences_skills_skills"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_experiences_skills_skills" RENAME TO "experiences_skills_skills"`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_54957c4ce34cebce0c6f152b87" ON "experiences_skills_skills" ("experiencesId") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_b39ff48a29419ea48077b619c4" ON "experiences_skills_skills" ("skillsId") `);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_d8128e9b444108a09d81529ea0"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_5291aa5a2295552d375007fefe"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "temporary_projects_skills_skills" ("projectsId" varchar NOT NULL, "skillsId" varchar NOT NULL, CONSTRAINT "FK_d8128e9b444108a09d81529ea06" FOREIGN KEY ("projectsId") REFERENCES "projects" ("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "FK_5291aa5a2295552d375007fefee" FOREIGN KEY ("skillsId") REFERENCES "skills" ("id") ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY ("projectsId", "skillsId"))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "temporary_projects_skills_skills"("projectsId", "skillsId") SELECT "projectsId", "skillsId" FROM "projects_skills_skills"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "projects_skills_skills"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "temporary_projects_skills_skills" RENAME TO "projects_skills_skills"`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_d8128e9b444108a09d81529ea0" ON "projects_skills_skills" ("projectsId") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_5291aa5a2295552d375007fefe" ON "projects_skills_skills" ("skillsId") `);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`ALTER TABLE "profiles" RENAME TO "temporary_profiles"`);
|
await queryRunner.query(`DROP INDEX "IDX_5291aa5a2295552d375007fefe"`);
|
||||||
await queryRunner.query(`CREATE TABLE "profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_a0e37cd676d13d116f73d494ee" UNIQUE ("statusId"))`);
|
await queryRunner.query(`DROP INDEX "IDX_d8128e9b444108a09d81529ea0"`);
|
||||||
await queryRunner.query(`INSERT INTO "profiles"("id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_profiles"`);
|
await queryRunner.query(`ALTER TABLE "projects_skills_skills" RENAME TO "temporary_projects_skills_skills"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_profiles"`);
|
await queryRunner.query(`CREATE TABLE "projects_skills_skills" ("projectsId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("projectsId", "skillsId"))`);
|
||||||
await queryRunner.query(`ALTER TABLE "experiences" RENAME TO "temporary_experiences"`);
|
await queryRunner.query(`INSERT INTO "projects_skills_skills"("projectsId", "skillsId") SELECT "projectsId", "skillsId" FROM "temporary_projects_skills_skills"`);
|
||||||
await queryRunner.query(`CREATE TABLE "experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_23dfcd8f2d1b6585b848f840d5" UNIQUE ("statusId"))`);
|
await queryRunner.query(`DROP TABLE "temporary_projects_skills_skills"`);
|
||||||
await queryRunner.query(`INSERT INTO "experiences"("id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_experiences"`);
|
await queryRunner.query(`CREATE INDEX "IDX_5291aa5a2295552d375007fefe" ON "projects_skills_skills" ("skillsId") `);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_experiences"`);
|
await queryRunner.query(`CREATE INDEX "IDX_d8128e9b444108a09d81529ea0" ON "projects_skills_skills" ("projectsId") `);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_b39ff48a29419ea48077b619c4"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_54957c4ce34cebce0c6f152b87"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "experiences_skills_skills" RENAME TO "temporary_experiences_skills_skills"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "experiences_skills_skills" ("experiencesId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("experiencesId", "skillsId"))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "experiences_skills_skills"("experiencesId", "skillsId") SELECT "experiencesId", "skillsId" FROM "temporary_experiences_skills_skills"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_experiences_skills_skills"`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_b39ff48a29419ea48077b619c4" ON "experiences_skills_skills" ("skillsId") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_54957c4ce34cebce0c6f152b87" ON "experiences_skills_skills" ("experiencesId") `);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_36a9448df496235d81a7ceb089"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_8401800ec9c15b8f383ac8d9c0"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "profiles_skills_skills" RENAME TO "temporary_profiles_skills_skills"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "profiles_skills_skills" ("profilesId" varchar NOT NULL, "skillsId" varchar NOT NULL, PRIMARY KEY ("profilesId", "skillsId"))`);
|
||||||
|
await queryRunner.query(`INSERT INTO "profiles_skills_skills"("profilesId", "skillsId") SELECT "profilesId", "skillsId" FROM "temporary_profiles_skills_skills"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_profiles_skills_skills"`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_36a9448df496235d81a7ceb089" ON "profiles_skills_skills" ("skillsId") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_8401800ec9c15b8f383ac8d9c0" ON "profiles_skills_skills" ("profilesId") `);
|
||||||
await queryRunner.query(`ALTER TABLE "projects" RENAME TO "temporary_projects"`);
|
await queryRunner.query(`ALTER TABLE "projects" RENAME TO "temporary_projects"`);
|
||||||
await queryRunner.query(`CREATE TABLE "projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_5a833dfa646b99b852c67dd859" UNIQUE ("statusId"))`);
|
await queryRunner.query(`CREATE TABLE "projects" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "iconName" varchar NOT NULL, "order" integer NOT NULL, "summary" varchar NOT NULL, "repoUrl" varchar, "siteUrl" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
await queryRunner.query(`INSERT INTO "projects"("id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_projects"`);
|
await queryRunner.query(`INSERT INTO "projects"("id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "iconName", "order", "summary", "repoUrl", "siteUrl", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_projects"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_projects"`);
|
await queryRunner.query(`DROP TABLE "temporary_projects"`);
|
||||||
await queryRunner.query(`ALTER TABLE "skills" RENAME TO "temporary_skills"`);
|
await queryRunner.query(`ALTER TABLE "skills" RENAME TO "temporary_skills"`);
|
||||||
await queryRunner.query(`CREATE TABLE "skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar, CONSTRAINT "REL_168133e3158020b53392549d3e" UNIQUE ("rankId"))`);
|
await queryRunner.query(`CREATE TABLE "skills" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "categoryId" varchar NOT NULL, "levelId" integer NOT NULL, "rankId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
await queryRunner.query(`INSERT INTO "skills"("id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_skills"`);
|
await queryRunner.query(`INSERT INTO "skills"("id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "categoryId", "levelId", "rankId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_skills"`);
|
||||||
await queryRunner.query(`DROP TABLE "temporary_skills"`);
|
await queryRunner.query(`DROP TABLE "temporary_skills"`);
|
||||||
await queryRunner.query(`DROP TABLE "profiles"`);
|
await queryRunner.query(`ALTER TABLE "experiences" RENAME TO "temporary_experiences"`);
|
||||||
await queryRunner.query(`DROP TABLE "experiences"`);
|
await queryRunner.query(`CREATE TABLE "experiences" ("id" varchar PRIMARY KEY NOT NULL, "profileId" varchar NOT NULL, "companyName" varchar NOT NULL, "companyGeneric" varchar NOT NULL, "title" varchar NOT NULL, "startDate" datetime NOT NULL, "endDate" datetime, "summary" varchar, "statusId" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
|
await queryRunner.query(`INSERT INTO "experiences"("id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "profileId", "companyName", "companyGeneric", "title", "startDate", "endDate", "summary", "statusId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_experiences"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_experiences"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "profiles" RENAME TO "temporary_profiles"`);
|
||||||
|
await queryRunner.query(`CREATE TABLE "profiles" ("id" varchar PRIMARY KEY NOT NULL, "name" varchar NOT NULL, "headline" varchar NOT NULL, "summary" varchar NOT NULL, "statusId" integer NOT NULL, "userId" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "createdBy" varchar, "updated" datetime NOT NULL DEFAULT (datetime('now')), "updatedBy" varchar, "deleted" datetime, "deletedBy" varchar)`);
|
||||||
|
await queryRunner.query(`INSERT INTO "profiles"("id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy") SELECT "id", "name", "headline", "summary", "statusId", "userId", "created", "createdBy", "updated", "updatedBy", "deleted", "deletedBy" FROM "temporary_profiles"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_profiles"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_5291aa5a2295552d375007fefe"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_d8128e9b444108a09d81529ea0"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "projects_skills_skills"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_b39ff48a29419ea48077b619c4"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_54957c4ce34cebce0c6f152b87"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "experiences_skills_skills"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_36a9448df496235d81a7ceb089"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_8401800ec9c15b8f383ac8d9c0"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "profiles_skills_skills"`);
|
||||||
await queryRunner.query(`DROP TABLE "projects"`);
|
await queryRunner.query(`DROP TABLE "projects"`);
|
||||||
await queryRunner.query(`DROP TABLE "skills"`);
|
await queryRunner.query(`DROP TABLE "skills"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "experiences"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "profiles"`);
|
||||||
await queryRunner.query(`DROP TABLE "skill_ranks"`);
|
await queryRunner.query(`DROP TABLE "skill_ranks"`);
|
||||||
await queryRunner.query(`DROP TABLE "skill_levels"`);
|
await queryRunner.query(`DROP TABLE "skill_levels"`);
|
||||||
await queryRunner.query(`DROP TABLE "skill_categories"`);
|
await queryRunner.query(`DROP TABLE "skill_categories"`);
|
||||||
@@ -31,6 +31,7 @@ export class ExperienceController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
async create(@Body() experienceDto: ExperienceDto): Promise<ExperienceDto> {
|
async create(@Body() experienceDto: ExperienceDto): Promise<ExperienceDto> {
|
||||||
|
console.log(experienceDto)
|
||||||
try {
|
try {
|
||||||
return await this.experienceService.create(experienceDto);
|
return await this.experienceService.create(experienceDto);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -45,6 +46,7 @@ export class ExperienceController {
|
|||||||
@Param('id') id: string,
|
@Param('id') id: string,
|
||||||
@Body() ExperienceDto: ExperienceDto
|
@Body() ExperienceDto: ExperienceDto
|
||||||
) {
|
) {
|
||||||
|
console.log(ExperienceDto)
|
||||||
try {
|
try {
|
||||||
return await this.experienceService.update(id, ExperienceDto);
|
return await this.experienceService.update(id, ExperienceDto);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { SkillEntity } from "src/skill/skill.entity";
|
||||||
|
|
||||||
export class ExperienceDto {
|
export class ExperienceDto {
|
||||||
companyName: string;
|
companyName: string;
|
||||||
companyNameGeneric: string;
|
companyNameGeneric: string;
|
||||||
@@ -6,7 +8,7 @@ export class ExperienceDto {
|
|||||||
startDate: Date;
|
startDate: Date;
|
||||||
endDate?: Date;
|
endDate?: Date;
|
||||||
summary: string;
|
summary: string;
|
||||||
skills?: [];
|
skills?: SkillEntity[];
|
||||||
createdBy?: string;
|
createdBy?: string;
|
||||||
updatedBy?: string;
|
updatedBy?: string;
|
||||||
deletedBy?: string;
|
deletedBy?: string;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ProfileEntity } from '../profile/profile.entity'
|
import { ProfileEntity } from '../profile/profile.entity'
|
||||||
import { SkillEntity } from 'src/skill/skill.entity';
|
import { SkillEntity } from 'src/skill/skill.entity';
|
||||||
import { StatusEntity } from 'src/status/status.entity';
|
import { StatusEntity } from 'src/status/status.entity';
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, JoinColumn, ManyToOne, OneToMany, OneToOne, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, JoinColumn, ManyToOne, OneToMany, OneToOne, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, ManyToMany, JoinTable } from 'typeorm';
|
||||||
|
|
||||||
@Entity({ name: 'experiences' })
|
@Entity({ name: 'experiences' })
|
||||||
export class ExperienceEntity {
|
export class ExperienceEntity {
|
||||||
@@ -50,14 +50,15 @@ export class ExperienceEntity {
|
|||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
deletedBy: string;
|
deletedBy: string;
|
||||||
|
|
||||||
@OneToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
|
@ManyToOne(() => StatusEntity, (status: StatusEntity) => status.name )
|
||||||
skills: SkillEntity[];
|
@JoinColumn({ name: 'statusId' })
|
||||||
|
status: StatusEntity;
|
||||||
|
|
||||||
@ManyToOne(() => ProfileEntity, (profile: ProfileEntity) => profile.experiences)
|
@ManyToOne(() => ProfileEntity, (profile: ProfileEntity) => profile.experiences)
|
||||||
@JoinColumn({ name: 'profileId' })
|
@JoinColumn({ name: 'profileId' })
|
||||||
profile: ProfileEntity;
|
profile: ProfileEntity;
|
||||||
|
|
||||||
@OneToOne(() => StatusEntity, (status: StatusEntity) => status.name )
|
@ManyToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
|
||||||
@JoinColumn({ name: 'statusId' })
|
@JoinTable()
|
||||||
status: StatusEntity;
|
skills: SkillEntity[];
|
||||||
}
|
}
|
||||||
@@ -13,13 +13,13 @@ export class ExperienceService {
|
|||||||
async find(id: string): Promise<ExperienceEntity> {
|
async find(id: string): Promise<ExperienceEntity> {
|
||||||
return await this.experienceRepository.findOne({
|
return await this.experienceRepository.findOne({
|
||||||
where: { id: id },
|
where: { id: id },
|
||||||
relations: ['profile', 'status']
|
relations: ['profile', 'skills', 'status']
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(): Promise<ExperienceEntity[]> {
|
async findAll(): Promise<ExperienceEntity[]> {
|
||||||
return await this.experienceRepository.find({
|
return await this.experienceRepository.find({
|
||||||
relations: ['profile', 'status']
|
relations: ['profile', 'skills', 'status']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
body {
|
|
||||||
background-color: #f2f2f2;
|
|
||||||
}
|
|
||||||
@@ -38,7 +38,7 @@ export class ProfileController {
|
|||||||
return await this.profileService.findAll();
|
return await this.profileService.findAll();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const customError = error as CustomError;
|
const customError = error as CustomError;
|
||||||
|
console.log(error)
|
||||||
throw new HttpException(customError.message, customError.statusCode);
|
throw new HttpException(customError.message, customError.statusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { SkillEntity } from "src/skill/skill.entity";
|
||||||
|
|
||||||
export class ProfileDto {
|
export class ProfileDto {
|
||||||
name: string;
|
name: string;
|
||||||
headline: string;
|
headline: string;
|
||||||
|
skills: SkillEntity[];
|
||||||
|
statusId: number;
|
||||||
summary: string;
|
summary: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
statusId: number;
|
|
||||||
createdBy?: string;
|
createdBy?: string;
|
||||||
updatedBy?: string;
|
updatedBy?: string;
|
||||||
deletedBy?: string;
|
deletedBy?: string;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ExperienceEntity } from 'src/experience/experience.entity';
|
import { ExperienceEntity } from 'src/experience/experience.entity';
|
||||||
import { SkillEntity } from 'src/skill/skill.entity';
|
import { SkillEntity } from 'src/skill/skill.entity';
|
||||||
import { StatusEntity } from 'src/status/status.entity';
|
import { StatusEntity } from 'src/status/status.entity';
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, OneToOne, JoinColumn } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, OneToOne, JoinColumn, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
|
||||||
|
|
||||||
@Entity({ name: 'profiles' })
|
@Entity({ name: 'profiles' })
|
||||||
export class ProfileEntity {
|
export class ProfileEntity {
|
||||||
@@ -44,10 +44,11 @@ export class ProfileEntity {
|
|||||||
@OneToMany(() => ExperienceEntity, (experience: ExperienceEntity) => experience.profile)
|
@OneToMany(() => ExperienceEntity, (experience: ExperienceEntity) => experience.profile)
|
||||||
experiences: ExperienceEntity[]
|
experiences: ExperienceEntity[]
|
||||||
|
|
||||||
@OneToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
|
@ManyToOne(() => StatusEntity, (status: StatusEntity) => status.name )
|
||||||
skills: SkillEntity[];
|
|
||||||
|
|
||||||
@OneToOne(() => StatusEntity, (status: StatusEntity) => status.name )
|
|
||||||
@JoinColumn({ name: 'statusId' })
|
@JoinColumn({ name: 'statusId' })
|
||||||
status: StatusEntity;
|
status: StatusEntity;
|
||||||
|
|
||||||
|
@ManyToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
|
||||||
|
@JoinTable()
|
||||||
|
skills: SkillEntity[];
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ export class ProfileService {
|
|||||||
async find(id: string): Promise<ProfileEntity> {
|
async find(id: string): Promise<ProfileEntity> {
|
||||||
const profile = await this.profileRepository.findOne({
|
const profile = await this.profileRepository.findOne({
|
||||||
where: { id: id },
|
where: { id: id },
|
||||||
relations: ['status']
|
relations: ['skills', 'status']
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(profile);
|
console.log(profile);
|
||||||
@@ -22,7 +22,7 @@ export class ProfileService {
|
|||||||
|
|
||||||
async findAll(): Promise<ProfileEntity[]> {
|
async findAll(): Promise<ProfileEntity[]> {
|
||||||
return await this.profileRepository.find({
|
return await this.profileRepository.find({
|
||||||
relations: ['status']
|
relations: ['skills', 'status']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { SkillEntity } from "src/skill/skill.entity";
|
||||||
|
|
||||||
export class ProjectDto {
|
export class ProjectDto {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -6,7 +8,7 @@ export class ProjectDto {
|
|||||||
summary: string;
|
summary: string;
|
||||||
repoUrl?: string;
|
repoUrl?: string;
|
||||||
siteUrl?: string;
|
siteUrl?: string;
|
||||||
skills?: [];
|
skills?: SkillEntity[];
|
||||||
createdBy?: string;
|
createdBy?: string;
|
||||||
updatedBy?: string;
|
updatedBy?: string;
|
||||||
deletedBy?: string;
|
deletedBy?: string;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SkillEntity } from 'src/skill/skill.entity';
|
import { SkillEntity } from 'src/skill/skill.entity';
|
||||||
import { StatusEntity } from 'src/status/status.entity';
|
import { StatusEntity } from 'src/status/status.entity';
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, OneToOne, JoinColumn, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, OneToOne, JoinColumn, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
|
||||||
|
|
||||||
@Entity({ name: 'projects' })
|
@Entity({ name: 'projects' })
|
||||||
export class ProjectEntity {
|
export class ProjectEntity {
|
||||||
@@ -46,10 +46,11 @@ export class ProjectEntity {
|
|||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
deletedBy: string
|
deletedBy: string
|
||||||
|
|
||||||
@OneToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
|
@ManyToOne(() => StatusEntity, (status: StatusEntity) => status.name )
|
||||||
skills: SkillEntity[];
|
|
||||||
|
|
||||||
@OneToOne(() => StatusEntity, (status: StatusEntity) => status.name )
|
|
||||||
@JoinColumn({ name: 'statusId' })
|
@JoinColumn({ name: 'statusId' })
|
||||||
status: StatusEntity;
|
status: StatusEntity;
|
||||||
|
|
||||||
|
@ManyToMany(() => SkillEntity, (skill: SkillEntity) => skill.name )
|
||||||
|
@JoinTable()
|
||||||
|
skills: SkillEntity[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,16 +13,15 @@ export class ProjectService {
|
|||||||
async find(id: string): Promise<ProjectEntity> {
|
async find(id: string): Promise<ProjectEntity> {
|
||||||
const project = await this.projectRepository.findOne({
|
const project = await this.projectRepository.findOne({
|
||||||
where: { id: id },
|
where: { id: id },
|
||||||
relations: ['status']
|
relations: ['skills', 'status']
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(project);
|
|
||||||
return project;
|
return project;
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(): Promise<ProjectEntity[]> {
|
async findAll(): Promise<ProjectEntity[]> {
|
||||||
return await this.projectRepository.find({
|
return await this.projectRepository.find({
|
||||||
relations: ['status']
|
relations: ['skills', 'status']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,5 @@ export class SkillLevelEntity {
|
|||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
deletedBy: string;
|
deletedBy: string;
|
||||||
|
|
||||||
@OneToMany(() => SkillEntity, (skill: SkillEntity) => skill.name)
|
|
||||||
skills: SkillEntity[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { SkillCategoryEntity } from 'src/skill/skill-category.entity';
|
|||||||
import { Entity, PrimaryGeneratedColumn, Column, JoinColumn, ManyToOne, ManyToMany, OneToOne, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, JoinColumn, ManyToOne, ManyToMany, OneToOne, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';
|
||||||
import { SkillLevelEntity } from './skill-level.entity';
|
import { SkillLevelEntity } from './skill-level.entity';
|
||||||
import { SkillRankEntity } from './skill-rank.entity';
|
import { SkillRankEntity } from './skill-rank.entity';
|
||||||
|
import { ExperienceEntity } from 'src/experience/experience.entity';
|
||||||
|
|
||||||
@Entity({ name: 'skills' })
|
@Entity({ name: 'skills' })
|
||||||
export class SkillEntity {
|
export class SkillEntity {
|
||||||
@@ -42,11 +43,14 @@ export class SkillEntity {
|
|||||||
@JoinColumn({ name: 'categoryId' })
|
@JoinColumn({ name: 'categoryId' })
|
||||||
category: SkillCategoryEntity;
|
category: SkillCategoryEntity;
|
||||||
|
|
||||||
@OneToOne(() => SkillRankEntity, (rank: SkillRankEntity) => rank.name)
|
@ManyToOne(() => SkillRankEntity, (rank: SkillRankEntity) => rank.name)
|
||||||
@JoinColumn({ name: 'rankId' })
|
@JoinColumn({ name: 'rankId' })
|
||||||
rank: SkillRankEntity;
|
rank: SkillRankEntity;
|
||||||
|
|
||||||
@ManyToOne(() => SkillLevelEntity, (level: SkillLevelEntity) => level.name)
|
@ManyToOne(() => SkillLevelEntity, (level: SkillLevelEntity) => level.name)
|
||||||
@JoinColumn({ name: 'levelId' })
|
@JoinColumn({ name: 'levelId' })
|
||||||
level: SkillLevelEntity;
|
level: SkillLevelEntity;
|
||||||
|
|
||||||
|
@ManyToMany(() => ExperienceEntity, (experience: ExperienceEntity) => experience.skills)
|
||||||
|
experiences: ExperienceEntity[]
|
||||||
}
|
}
|
||||||
@@ -9,11 +9,15 @@ import { AxiosError, AxiosResponse } from "axios";
|
|||||||
import { ScreenSize } from "../../enums/screenSize";
|
import { ScreenSize } from "../../enums/screenSize";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faSave, faXmark } from "@fortawesome/free-solid-svg-icons";
|
import { faSave, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { useAppContext } from "../../hooks/appContext/UseAppContext";
|
||||||
|
|
||||||
const SkillCategoryForm = ({ isDrawerOpen, mode, onOpenClose, categoryId }: SkillCategoryFormProps) => {
|
const SkillCategoryForm = ({ isDrawerOpen, mode, onOpenClose, categoryId }: SkillCategoryFormProps) => {
|
||||||
const [state, dispatch] = useReducer(reducer, initialState);
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
|
const appContext = useAppContext();
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
name: ''
|
name: '',
|
||||||
|
createdBy: '',
|
||||||
|
updatedBy: ''
|
||||||
}
|
}
|
||||||
const methods = useForm({
|
const methods = useForm({
|
||||||
defaultValues: defaultValues
|
defaultValues: defaultValues
|
||||||
@@ -26,14 +30,25 @@ const SkillCategoryForm = ({ isDrawerOpen, mode, onOpenClose, categoryId }: Skil
|
|||||||
onOpenClose(FormMode.CANCEL)
|
onOpenClose(FormMode.CANCEL)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSubmit = async (data: unknown) => {
|
const onSubmit = async (data: any) => {
|
||||||
try {
|
try {
|
||||||
dispatch({ type: 'SET_IS_LOADING', payload: true })
|
dispatch({ type: 'SET_IS_LOADING', payload: true })
|
||||||
|
|
||||||
if (!categoryId) {
|
if (!categoryId) {
|
||||||
await httpClient.post(`api/skill-categories`, data);
|
const newData = {
|
||||||
|
...data,
|
||||||
|
createdBy: appContext.state.userProfile.userPrincipalName,
|
||||||
|
updatedBy: appContext.state.userProfile.userPrincipalName
|
||||||
|
}
|
||||||
|
|
||||||
|
await httpClient.post(`api/skill-categories`, newData);
|
||||||
} else {
|
} else {
|
||||||
await httpClient.put(`api/skill-categories`)
|
const newData = {
|
||||||
|
...data,
|
||||||
|
updatedBy: appContext.state.userProfile.userPrincipalName
|
||||||
|
}
|
||||||
|
|
||||||
|
await httpClient.put(`api/skill-categories`, newData)
|
||||||
}
|
}
|
||||||
|
|
||||||
methods.reset(defaultValues);
|
methods.reset(defaultValues);
|
||||||
|
|||||||
@@ -9,14 +9,18 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|||||||
import { faSave, faXmark } from '@fortawesome/free-solid-svg-icons';
|
import { faSave, faXmark } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { ScreenSize } from '../../enums/screenSize';
|
import { ScreenSize } from '../../enums/screenSize';
|
||||||
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
|
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
|
||||||
|
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||||
|
|
||||||
const SkillForm = ({ isDrawerOpen, mode, onOpenClose, skillId }: SkillFormProps) => {
|
const SkillForm = ({ isDrawerOpen, mode, onOpenClose, skillId }: SkillFormProps) => {
|
||||||
const [state, dispatch] = useReducer(reducer, initialState);
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
|
const appContext = useAppContext();
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
name: '',
|
name: '',
|
||||||
categoryId: '',
|
categoryId: '',
|
||||||
levelId: '',
|
levelId: '',
|
||||||
rankId: ''
|
rankId: '',
|
||||||
|
createdBy: '',
|
||||||
|
updatedBy: ''
|
||||||
}
|
}
|
||||||
const methods = useForm({
|
const methods = useForm({
|
||||||
defaultValues: defaultValues
|
defaultValues: defaultValues
|
||||||
@@ -29,14 +33,25 @@ const SkillForm = ({ isDrawerOpen, mode, onOpenClose, skillId }: SkillFormProps)
|
|||||||
onOpenClose(FormMode.CANCEL);
|
onOpenClose(FormMode.CANCEL);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = async (data: unknown) => {
|
const onSubmit = async (data: any) => {
|
||||||
try {
|
try {
|
||||||
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
||||||
console.log(data)
|
console.log(data)
|
||||||
if (!skillId) {
|
if (!skillId) {
|
||||||
await httpClient.post(`api/skills`, data);
|
const newData = {
|
||||||
|
...data,
|
||||||
|
createdBy: appContext.state.userProfile.userPrincipalName,
|
||||||
|
updatedBy: appContext.state.userProfile.userPrincipalName
|
||||||
|
}
|
||||||
|
|
||||||
|
await httpClient.post(`api/skills`, newData);
|
||||||
} else {
|
} else {
|
||||||
await httpClient.put(`api/skills/skill/${skillId}`, data);
|
const newData = {
|
||||||
|
...data,
|
||||||
|
updatedBy: appContext.state.userProfile.userPrincipalName
|
||||||
|
}
|
||||||
|
|
||||||
|
await httpClient.put(`api/skills/skill/${skillId}`, newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
methods.reset(defaultValues);
|
methods.reset(defaultValues);
|
||||||
|
|||||||
@@ -12,14 +12,17 @@ import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
|
|||||||
import { Profile } from '../profiles/Profile.interface';
|
import { Profile } from '../profiles/Profile.interface';
|
||||||
import { useProfiles } from '../../hooks/profiles/UseProfiles';
|
import { useProfiles } from '../../hooks/profiles/UseProfiles';
|
||||||
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||||
import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headlessui/react';
|
|
||||||
import { useSkills } from '../../hooks/skills/UseSkills';
|
import { useSkills } from '../../hooks/skills/UseSkills';
|
||||||
|
import MultiSelectDropdown from '../multiSelectDropdown/MultiSelectDropdown';
|
||||||
|
import { Skill } from '../skills/Skill.interface';
|
||||||
|
import { Experience } from '../experiences/Experience.interface';
|
||||||
|
|
||||||
const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: ExperienceFormProps) => {
|
const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: ExperienceFormProps) => {
|
||||||
const [state, dispatch] = useReducer(reducer, initialState);
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
const appContext = useAppContext();
|
const appContext = useAppContext();
|
||||||
const { profiles } = useProfiles();
|
const { profiles } = useProfiles();
|
||||||
const { skills } = useSkills();
|
const { skills } = useSkills();
|
||||||
|
const experienceSkills: Skill[] = []
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
profileId: '',
|
profileId: '',
|
||||||
companyName: '',
|
companyName: '',
|
||||||
@@ -27,7 +30,7 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
|
|||||||
title: '',
|
title: '',
|
||||||
startDate: '',
|
startDate: '',
|
||||||
endDate: '',
|
endDate: '',
|
||||||
skills: [],
|
skills: experienceSkills,
|
||||||
summary: '',
|
summary: '',
|
||||||
statusId: 1,
|
statusId: 1,
|
||||||
createdBy: '',
|
createdBy: '',
|
||||||
@@ -36,9 +39,23 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
|
|||||||
const methods = useForm({
|
const methods = useForm({
|
||||||
defaultValues: defaultValues
|
defaultValues: defaultValues
|
||||||
});
|
});
|
||||||
// const watchRepoName = methods.watch(['repoName'])
|
|
||||||
const { screenSize } = useBreakpoints();
|
const { screenSize } = useBreakpoints();
|
||||||
|
|
||||||
|
const onSetSelectedSkills = (selectedSkill: Skill) => {
|
||||||
|
const selectedSkillExists = state.selectedSkills.find((skill) => skill.id === selectedSkill.id)
|
||||||
|
let newSelectedSkills: Skill[];
|
||||||
|
|
||||||
|
if (selectedSkillExists) {
|
||||||
|
newSelectedSkills = state.selectedSkills.filter((skill) => skill.id !== selectedSkillExists.id)
|
||||||
|
} else {
|
||||||
|
newSelectedSkills = [...state.selectedSkills, selectedSkill]
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({ type: 'SET_SELECTED_SKILLS', payload: newSelectedSkills })
|
||||||
|
methods.setValue('skills', newSelectedSkills)
|
||||||
|
}
|
||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
methods.reset(defaultValues);
|
methods.reset(defaultValues);
|
||||||
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
||||||
@@ -92,6 +109,10 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
|
|||||||
);
|
);
|
||||||
const experience = response.data;
|
const experience = response.data;
|
||||||
|
|
||||||
|
if (experience.skills) {
|
||||||
|
dispatch({ type: 'SET_SELECTED_SKILLS', payload: experience.skills })
|
||||||
|
}
|
||||||
|
|
||||||
methods.reset(experience);
|
methods.reset(experience);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const axiosError = error as AxiosError;
|
const axiosError = error as AxiosError;
|
||||||
@@ -127,7 +148,9 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
|
|||||||
}, [profiles]);
|
}, [profiles]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (skills) {
|
||||||
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
|
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
|
||||||
|
}
|
||||||
}, [skills])
|
}, [skills])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -296,23 +319,12 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
|
|||||||
<Controller
|
<Controller
|
||||||
name="skills"
|
name="skills"
|
||||||
control={methods.control}
|
control={methods.control}
|
||||||
render={({ field: { onChange, value } }) => (
|
render={() => (
|
||||||
// <input
|
<MultiSelectDropdown
|
||||||
// type='text'
|
skills={state.skillOptions}
|
||||||
// className='input w-full'
|
onChange={onSetSelectedSkills}
|
||||||
// disabled={state.isDisabled}
|
selectedSkills={state.selectedSkills}
|
||||||
// onChange={onChange}
|
/>
|
||||||
// value={value}
|
|
||||||
// />
|
|
||||||
<Listbox value={value} onChange={onChange}>
|
|
||||||
<ListboxOptions anchor='bottom'>
|
|
||||||
{state.skillOptions?.map((skill) => (
|
|
||||||
<ListboxOption key={skill.id} value={skill.id}>
|
|
||||||
{skill.name}
|
|
||||||
</ListboxOption>
|
|
||||||
))}
|
|
||||||
</ListboxOptions>
|
|
||||||
</Listbox>
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ export interface ExperienceFormState {
|
|||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
profileOptions: Profile[];
|
profileOptions: Profile[];
|
||||||
skillOptions: Skill[] | undefined;
|
selectedSkills: Skill[];
|
||||||
|
skillOptions: Skill[];
|
||||||
}
|
}
|
||||||
@@ -7,13 +7,15 @@ type Action =
|
|||||||
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
||||||
| { type: 'SET_IS_LOADING'; payload: boolean }
|
| { type: 'SET_IS_LOADING'; payload: boolean }
|
||||||
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] }
|
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] }
|
||||||
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] | undefined };
|
| { type: 'SET_SELECTED_SKILLS'; payload: Skill[] }
|
||||||
|
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] };
|
||||||
|
|
||||||
export const initialState: ExperienceFormState = {
|
export const initialState: ExperienceFormState = {
|
||||||
error: undefined,
|
error: undefined,
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
profileOptions: [],
|
profileOptions: [],
|
||||||
|
selectedSkills: [],
|
||||||
skillOptions: []
|
skillOptions: []
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,6 +48,12 @@ export const reducer = (
|
|||||||
profileOptions: action.payload
|
profileOptions: action.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 'SET_SELECTED_SKILLS': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
selectedSkills: action.payload
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'SET_SKILL_OPTIONS': {
|
case 'SET_SKILL_OPTIONS': {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export interface Experience {
|
|||||||
startDate: Date;
|
startDate: Date;
|
||||||
endDate?: Date;
|
endDate?: Date;
|
||||||
summary?: string;
|
summary?: string;
|
||||||
skills: Skill[];
|
skills?: Skill[];
|
||||||
profile: Profile;
|
profile: Profile;
|
||||||
status: Status;
|
status: Status;
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,7 @@ import { useUserRole } from '../../hooks/userRole/UseUserRole';
|
|||||||
import Alert from '../../alert/Alert';
|
import Alert from '../../alert/Alert';
|
||||||
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
|
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
import { Profile } from '../profiles/Profile.interface';
|
import { Profile } from '../profiles/Profile.interface';
|
||||||
|
import { Skill } from '../skills/Skill.interface';
|
||||||
|
|
||||||
interface ActionsProps {
|
interface ActionsProps {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -166,6 +167,17 @@ const Experiences = () => {
|
|||||||
accessorKey: 'summary',
|
accessorKey: 'summary',
|
||||||
header: 'Summary'
|
header: 'Summary'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'skills',
|
||||||
|
accessorKey: 'skills',
|
||||||
|
header: 'Skills',
|
||||||
|
cell: (info: CellContext<Experience, unknown>) => {
|
||||||
|
const skills = info.getValue() as Skill[];
|
||||||
|
const skillsString: string = skills.map((skill) => skill.name).join(', ')
|
||||||
|
|
||||||
|
return skillsString
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'status',
|
id: 'status',
|
||||||
accessorKey: 'status',
|
accessorKey: 'status',
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { MultiSelectDropdownProps } from "./MultiSelectDropdownProps";
|
import { MultiSelectDropdownProps } from "./MultiSelectDropdownProps";
|
||||||
|
import { Skill } from "../skills/Skill.interface";
|
||||||
|
|
||||||
const MultiSelectDropdown = ({ options }: MultiSelectDropdownProps) => {
|
const MultiSelectDropdown = ({ onChange, skills, selectedSkills }: MultiSelectDropdownProps) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [selectedValues, setSelectedValues] = useState([])
|
// const [selectedValues, setSelectedValues] = useState([])
|
||||||
const dropdownRef = useRef(null)
|
const dropdownRef = useRef(null)
|
||||||
|
|
||||||
const handleToggleOption = (value: any) => {
|
const handleToggleOption = (value: any) => {
|
||||||
let updated;
|
// let updated;
|
||||||
|
|
||||||
if (selectedValues.includes(value)) {
|
// if (selectedValues.includes(value)) {
|
||||||
updated = selectedValues.filter((item) => item !== value);
|
// updated = selectedValues.filter((item) => item !== value);
|
||||||
} else {
|
// } else {
|
||||||
updated = [...selectedValues, value];
|
// updated = [...selectedValues, value];
|
||||||
}
|
// }
|
||||||
|
|
||||||
setSelectedValues(updated);
|
// setSelectedValues(updated);
|
||||||
if (onChange) onChange(updated)
|
// if (onChange) onChange(updated)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRemoveBadge = (event, value) => {
|
const handleRemoveBadge = (event, value) => {
|
||||||
event.stopPropagation();
|
// event.stopPropagation();
|
||||||
|
|
||||||
const updated = selectedValues.filter((item) => item !== value);
|
// const updated = selectedValues.filter((item) => item !== value);
|
||||||
|
|
||||||
setSelectedValues(updated)
|
// setSelectedValues(updated)
|
||||||
|
|
||||||
if (onChange) onchange(updated)
|
// if (onChange) onchange(updated)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -50,21 +51,15 @@ const MultiSelectDropdown = ({ options }: MultiSelectDropdownProps) => {
|
|||||||
className="select select-bordered w-full h-auto min-h-12 flex flex-wrap items-center gap-1 p-2 bg-base-100 text-left cursor-pointer"
|
className="select select-bordered w-full h-auto min-h-12 flex flex-wrap items-center gap-1 p-2 bg-base-100 text-left cursor-pointer"
|
||||||
onClick={() => setIsOpen(!isOpen)}
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
>
|
>
|
||||||
{selectedValues.length === 0 ? (
|
{selectedSkills.length === 0 ? (
|
||||||
<span className="text-base-content/50"></span>
|
<span className="text-base-content/50"></span>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{selectedValues.map((val) => {
|
{selectedSkills.map((selectedSkill: Skill) => {
|
||||||
const option = options.find((o: any) => o.value === val);
|
const option = skills.find((skill: Skill) => skill.id === selectedSkill.id);
|
||||||
return (
|
return (
|
||||||
<div key={val} className="badge badge-primary gap-1 py-3 px-2">
|
<div key={selectedSkill.id} className="badge badge-primary gap-1 py-3 px-2">
|
||||||
{option?.label || val}
|
{option?.name || selectedSkill.name}
|
||||||
<button
|
|
||||||
onClick={(event) => handleRemoveBadge(event, val)}
|
|
||||||
className="btn btn-ghost btn-xs p-0 min-h-0 h-auto text-primary-content hover:bg-transparent"
|
|
||||||
>
|
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -75,16 +70,16 @@ const MultiSelectDropdown = ({ options }: MultiSelectDropdownProps) => {
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className="dropdown-content menu p-2 shadow-lg bg-base-100 rounded-box w-full max-h-60 overflow-y-auto z-[1] border border-base-200"
|
className="dropdown-content menu p-2 shadow-lg bg-base-100 rounded-box w-full max-h-60 overflow-y-auto z-[1] border border-base-200"
|
||||||
>
|
>
|
||||||
{options.map((option) => (
|
{skills.map((skill) => (
|
||||||
<li key={option.value} className="p-0">
|
<li key={skill.id} className="p-0">
|
||||||
<label className="label cursor-pointer justify-start gap-3 px-4 py-2 hover:bg-base-200 rounded-lg w-full">
|
<label className="label cursor-pointer justify-start gap-3 px-4 py-2 hover:bg-base-200 rounded-lg w-full">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="checkbox checkbox-primary checkbox-sm"
|
className="checkbox checkbox-primary checkbox-sm"
|
||||||
checked={selectedValues.includes(option.value)}
|
checked={selectedSkills.includes(skill)}
|
||||||
onChange={() => handleToggleOption(option.value)}
|
onChange={() => onChange(skill)}
|
||||||
/>
|
/>
|
||||||
<span className="label-text text-base-content">{option.label}</span>
|
<span className="label-text text-base-content">{skill.name}</span>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
import { Skill } from "../skills/Skill.interface";
|
||||||
|
|
||||||
export interface MultiSelectDropdownProps {
|
export interface MultiSelectDropdownProps {
|
||||||
options: { label: string; value: string }[];
|
onChange: (selectedSkill: Skill) => void;
|
||||||
|
skills: Skill[];
|
||||||
|
selectedSkills: Skill[];
|
||||||
}
|
}
|
||||||
@@ -10,15 +10,21 @@ import { faSave, faXmark } from '@fortawesome/free-solid-svg-icons';
|
|||||||
import { ScreenSize } from '../../enums/screenSize';
|
import { ScreenSize } from '../../enums/screenSize';
|
||||||
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
|
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
|
||||||
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||||
|
import { Skill } from '../skills/Skill.interface';
|
||||||
|
import { useSkills } from '../../hooks/skills/UseSkills';
|
||||||
|
import MultiSelectDropdown from '../multiSelectDropdown/MultiSelectDropdown';
|
||||||
|
|
||||||
const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileFormProps) => {
|
const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileFormProps) => {
|
||||||
const [state, dispatch] = useReducer(reducer, initialState);
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
const appContext = useAppContext();
|
const appContext = useAppContext();
|
||||||
|
const { skills } = useSkills();
|
||||||
|
const projectSkills: Skill[] = []
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
name: '',
|
name: '',
|
||||||
headline: '',
|
headline: '',
|
||||||
summary: '',
|
summary: '',
|
||||||
userId: '',
|
userId: '',
|
||||||
|
skills: projectSkills,
|
||||||
statusId: 1
|
statusId: 1
|
||||||
}
|
}
|
||||||
const methods = useForm({
|
const methods = useForm({
|
||||||
@@ -27,6 +33,20 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
|
|||||||
// const watchRepoName = methods.watch(['repoName'])
|
// const watchRepoName = methods.watch(['repoName'])
|
||||||
const { screenSize } = useBreakpoints();
|
const { screenSize } = useBreakpoints();
|
||||||
|
|
||||||
|
const onSetSelectedSkills = (selectedSkill: Skill) => {
|
||||||
|
const selectedSkillExists = state.selectedSkills.find((skill) => skill.id === selectedSkill.id)
|
||||||
|
let newSelectedSkills: Skill[];
|
||||||
|
|
||||||
|
if (selectedSkillExists) {
|
||||||
|
newSelectedSkills = state.selectedSkills.filter((skill) => skill.id !== selectedSkillExists.id)
|
||||||
|
} else {
|
||||||
|
newSelectedSkills = [...state.selectedSkills, selectedSkill]
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({ type: 'SET_SELECTED_SKILLS', payload: newSelectedSkills })
|
||||||
|
methods.setValue('skills', newSelectedSkills)
|
||||||
|
}
|
||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
methods.reset(defaultValues);
|
methods.reset(defaultValues);
|
||||||
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
||||||
@@ -80,9 +100,13 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
|
|||||||
const response: AxiosResponse = await httpClient.get(
|
const response: AxiosResponse = await httpClient.get(
|
||||||
`api/profiles/${profileId}`
|
`api/profiles/${profileId}`
|
||||||
);
|
);
|
||||||
const entry = response.data;
|
const profile = response.data;
|
||||||
|
|
||||||
methods.reset(entry);
|
if (profile.skills) {
|
||||||
|
dispatch({ type: 'SET_SELECTED_SKILLS', payload: profile.skills })
|
||||||
|
}
|
||||||
|
|
||||||
|
methods.reset(profile);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const axiosError = error as AxiosError;
|
const axiosError = error as AxiosError;
|
||||||
console.log(axiosError)
|
console.log(axiosError)
|
||||||
@@ -97,6 +121,12 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
|
|||||||
}
|
}
|
||||||
}, [profileId]);
|
}, [profileId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (skills) {
|
||||||
|
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
|
||||||
|
}
|
||||||
|
}, [skills])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='drawer drawer-end'>
|
<div className='drawer drawer-end'>
|
||||||
<input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={isDrawerOpen} />
|
<input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={isDrawerOpen} />
|
||||||
@@ -175,6 +205,22 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={`col-span-3 self-center after:content-['*'] after:ms-0.5`}>
|
||||||
|
<span>Skills</span>
|
||||||
|
</div>
|
||||||
|
<div className='col-span-9'>
|
||||||
|
<Controller
|
||||||
|
name="skills"
|
||||||
|
control={methods.control}
|
||||||
|
render={() => (
|
||||||
|
<MultiSelectDropdown
|
||||||
|
skills={state.skillOptions}
|
||||||
|
onChange={onSetSelectedSkills}
|
||||||
|
selectedSkills={state.selectedSkills}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className='col-span-12 justify-self-end self-center'>
|
<div className='col-span-12 justify-self-end self-center'>
|
||||||
<button
|
<button
|
||||||
className='btn'
|
className='btn'
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
import { Skill } from "../skills/Skill.interface";
|
||||||
|
|
||||||
export interface ProfileFormState {
|
export interface ProfileFormState {
|
||||||
error: string | undefined;
|
error: string | undefined;
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
|
selectedSkills: Skill[];
|
||||||
|
skillOptions: Skill[];
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
import { Profile } from "../profiles/Profile.interface";
|
import { Profile } from "../profiles/Profile.interface";
|
||||||
|
import { Skill } from "../skills/Skill.interface";
|
||||||
import { ProfileFormState } from "./ProfileFormState.interface"
|
import { ProfileFormState } from "./ProfileFormState.interface"
|
||||||
|
|
||||||
type Action =
|
type Action =
|
||||||
| { type: 'SET_ERROR'; payload: string | undefined }
|
| { type: 'SET_ERROR'; payload: string | undefined }
|
||||||
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
||||||
| { type: 'SET_IS_LOADING'; payload: boolean };
|
| { type: 'SET_IS_LOADING'; payload: boolean }
|
||||||
|
| { type: 'SET_SELECTED_SKILLS'; payload: Skill[] }
|
||||||
|
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] };
|
||||||
|
|
||||||
export const initialState: ProfileFormState = {
|
export const initialState: ProfileFormState = {
|
||||||
error: undefined,
|
error: undefined,
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
isLoading: true
|
isLoading: true,
|
||||||
|
selectedSkills: [],
|
||||||
|
skillOptions: []
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reducer = (
|
export const reducer = (
|
||||||
@@ -34,6 +39,18 @@ export const reducer = (
|
|||||||
...state,
|
...state,
|
||||||
isLoading: action.payload
|
isLoading: action.payload
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
case 'SET_SELECTED_SKILLS': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
selectedSkills: action.payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'SET_SKILL_OPTIONS': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
skillOptions: action.payload
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
return state;
|
return state;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { UserRole } from '../../enums/userRole';
|
|||||||
import { useUserRole } from '../../hooks/userRole/UseUserRole';
|
import { useUserRole } from '../../hooks/userRole/UseUserRole';
|
||||||
import Alert from '../../alert/Alert';
|
import Alert from '../../alert/Alert';
|
||||||
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
|
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
|
import { Skill } from '../skills/Skill.interface';
|
||||||
|
|
||||||
interface ActionsProps {
|
interface ActionsProps {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -144,6 +145,17 @@ const Profiles = () => {
|
|||||||
accessorKey: 'summary',
|
accessorKey: 'summary',
|
||||||
header: 'Summary'
|
header: 'Summary'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'skills',
|
||||||
|
accessorKey: 'skills',
|
||||||
|
header: 'Skills',
|
||||||
|
cell: (info: CellContext<Profile, unknown>) => {
|
||||||
|
const skills = info.getValue() as Skill[];
|
||||||
|
const skillsString: string = skills.map((skill) => skill.name).join(', ')
|
||||||
|
|
||||||
|
return skillsString
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'status',
|
id: 'status',
|
||||||
accessorKey: 'status',
|
accessorKey: 'status',
|
||||||
|
|||||||
@@ -11,10 +11,15 @@ import { ScreenSize } from '../../enums/screenSize';
|
|||||||
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
|
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
|
||||||
import { useProfiles } from '../../hooks/profiles/UseProfiles';
|
import { useProfiles } from '../../hooks/profiles/UseProfiles';
|
||||||
import { Profile } from '../profiles/Profile.interface';
|
import { Profile } from '../profiles/Profile.interface';
|
||||||
|
import { Skill } from '../skills/Skill.interface';
|
||||||
|
import { useSkills } from '../../hooks/skills/UseSkills';
|
||||||
|
import MultiSelectDropdown from '../multiSelectDropdown/MultiSelectDropdown';
|
||||||
|
|
||||||
const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectFormProps) => {
|
const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectFormProps) => {
|
||||||
const [state, dispatch] = useReducer(reducer, initialState);
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
const { profiles } = useProfiles()
|
const { profiles } = useProfiles();
|
||||||
|
const { skills } = useSkills();
|
||||||
|
const projectSkills: Skill[] = []
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
profileId: '',
|
profileId: '',
|
||||||
name: '',
|
name: '',
|
||||||
@@ -23,6 +28,7 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
|
|||||||
repoUrl: '',
|
repoUrl: '',
|
||||||
siteUrl: '',
|
siteUrl: '',
|
||||||
order: '',
|
order: '',
|
||||||
|
skills: projectSkills,
|
||||||
statusId: 1
|
statusId: 1
|
||||||
}
|
}
|
||||||
const methods = useForm({
|
const methods = useForm({
|
||||||
@@ -31,6 +37,20 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
|
|||||||
// const watchRepoName = methods.watch(['repoName'])
|
// const watchRepoName = methods.watch(['repoName'])
|
||||||
const { screenSize } = useBreakpoints();
|
const { screenSize } = useBreakpoints();
|
||||||
|
|
||||||
|
const onSetSelectedSkills = (selectedSkill: Skill) => {
|
||||||
|
const selectedSkillExists = state.selectedSkills.find((skill) => skill.id === selectedSkill.id)
|
||||||
|
let newSelectedSkills: Skill[];
|
||||||
|
|
||||||
|
if (selectedSkillExists) {
|
||||||
|
newSelectedSkills = state.selectedSkills.filter((skill) => skill.id !== selectedSkillExists.id)
|
||||||
|
} else {
|
||||||
|
newSelectedSkills = [...state.selectedSkills, selectedSkill]
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({ type: 'SET_SELECTED_SKILLS', payload: newSelectedSkills })
|
||||||
|
methods.setValue('skills', newSelectedSkills)
|
||||||
|
}
|
||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
methods.reset(defaultValues);
|
methods.reset(defaultValues);
|
||||||
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
||||||
@@ -44,7 +64,7 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
|
|||||||
if (!projectId) {
|
if (!projectId) {
|
||||||
await httpClient.post(`api/projects`, data);
|
await httpClient.post(`api/projects`, data);
|
||||||
} else {
|
} else {
|
||||||
await httpClient.put(`api/projects/project/${projectId}`, data);
|
await httpClient.put(`api/projects/${projectId}`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
methods.reset(defaultValues);
|
methods.reset(defaultValues);
|
||||||
@@ -77,11 +97,15 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
|
|||||||
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
||||||
|
|
||||||
const response: AxiosResponse = await httpClient.get(
|
const response: AxiosResponse = await httpClient.get(
|
||||||
`api/projects/project/${projectId}`
|
`api/projects/${projectId}`
|
||||||
);
|
);
|
||||||
const entry = response.data;
|
const project = response.data;
|
||||||
|
|
||||||
methods.reset(entry);
|
if (project.skills) {
|
||||||
|
dispatch({ type: 'SET_SELECTED_SKILLS', payload: project.skills })
|
||||||
|
}
|
||||||
|
|
||||||
|
methods.reset(project);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const axiosError = error as AxiosError;
|
const axiosError = error as AxiosError;
|
||||||
console.log(axiosError)
|
console.log(axiosError)
|
||||||
@@ -107,13 +131,20 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
|
|||||||
summary: '',
|
summary: '',
|
||||||
userId: '',
|
userId: '',
|
||||||
experiences: [],
|
experiences: [],
|
||||||
skills: []
|
skills: [],
|
||||||
|
status: null
|
||||||
})
|
})
|
||||||
|
|
||||||
dispatch({ type: 'SET_PROFILE_OPTIONS', payload: newProfileOptions });
|
dispatch({ type: 'SET_PROFILE_OPTIONS', payload: newProfileOptions });
|
||||||
}
|
}
|
||||||
}, [profiles]);
|
}, [profiles]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (skills) {
|
||||||
|
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
|
||||||
|
}
|
||||||
|
}, [skills])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='drawer drawer-end'>
|
<div className='drawer drawer-end'>
|
||||||
<input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={isDrawerOpen} />
|
<input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={isDrawerOpen} />
|
||||||
@@ -272,6 +303,22 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={`col-span-3 self-center after:content-['*'] after:ms-0.5`}>
|
||||||
|
<span>Skills</span>
|
||||||
|
</div>
|
||||||
|
<div className='col-span-9'>
|
||||||
|
<Controller
|
||||||
|
name="skills"
|
||||||
|
control={methods.control}
|
||||||
|
render={() => (
|
||||||
|
<MultiSelectDropdown
|
||||||
|
skills={state.skillOptions}
|
||||||
|
onChange={onSetSelectedSkills}
|
||||||
|
selectedSkills={state.selectedSkills}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className='col-span-12 justify-self-end self-center'>
|
<div className='col-span-12 justify-self-end self-center'>
|
||||||
<button
|
<button
|
||||||
className='btn'
|
className='btn'
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import { Profile } from "../profiles/Profile.interface";
|
import { Profile } from "../profiles/Profile.interface";
|
||||||
|
import { Skill } from "../skills/Skill.interface";
|
||||||
|
|
||||||
export interface ProjectFormState {
|
export interface ProjectFormState {
|
||||||
error: string | undefined;
|
error: string | undefined;
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
profileOptions: Profile[];
|
profileOptions: Profile[];
|
||||||
|
selectedSkills: Skill[];
|
||||||
|
skillOptions: Skill[];
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,22 @@
|
|||||||
import { Profile } from "../profiles/Profile.interface";
|
import { Profile } from "../profiles/Profile.interface";
|
||||||
|
import { Skill } from "../skills/Skill.interface";
|
||||||
import { ProjectFormState } from "./ProjectFormState.interface"
|
import { ProjectFormState } from "./ProjectFormState.interface"
|
||||||
|
|
||||||
type Action =
|
type Action =
|
||||||
| { type: 'SET_ERROR'; payload: string | undefined }
|
| { type: 'SET_ERROR'; payload: string | undefined }
|
||||||
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
||||||
| { type: 'SET_IS_LOADING'; payload: boolean }
|
| { type: 'SET_IS_LOADING'; payload: boolean }
|
||||||
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] };
|
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] }
|
||||||
|
| { type: 'SET_SELECTED_SKILLS'; payload: Skill[] }
|
||||||
|
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] };
|
||||||
|
|
||||||
export const initialState: ProjectFormState = {
|
export const initialState: ProjectFormState = {
|
||||||
error: undefined,
|
error: undefined,
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
profileOptions: []
|
profileOptions: [],
|
||||||
|
selectedSkills: [],
|
||||||
|
skillOptions: []
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reducer = (
|
export const reducer = (
|
||||||
@@ -43,6 +48,18 @@ export const reducer = (
|
|||||||
profileOptions: action.payload
|
profileOptions: action.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 'SET_SELECTED_SKILLS': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
selectedSkills: action.payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'SET_SKILL_OPTIONS': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
skillOptions: action.payload
|
||||||
|
}
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,4 @@
|
|||||||
import { Project } from './Project.interface';
|
import { Project } from './Project.interface';
|
||||||
// import {
|
|
||||||
// Alert,
|
|
||||||
// Box,
|
|
||||||
// Button,
|
|
||||||
// Card,
|
|
||||||
// CardActions,
|
|
||||||
// CardContent,
|
|
||||||
// CardHeader,
|
|
||||||
// Container,
|
|
||||||
// Grid,
|
|
||||||
// Icon,
|
|
||||||
// IconName,
|
|
||||||
// Skeleton,
|
|
||||||
// Stack,
|
|
||||||
// Typography
|
|
||||||
// } from '@noahspan/noahspan-components';
|
|
||||||
import { FormMode } from '../../enums/formMode';
|
import { FormMode } from '../../enums/formMode';
|
||||||
import { useEffect, useReducer } from 'react';
|
import { useEffect, useReducer } from 'react';
|
||||||
import { initialState, reducer } from './reducer';
|
import { initialState, reducer } from './reducer';
|
||||||
@@ -32,6 +16,7 @@ import { UserRole } from '../../enums/userRole';
|
|||||||
import { useUserRole } from '../../hooks/userRole/UseUserRole';
|
import { useUserRole } from '../../hooks/userRole/UseUserRole';
|
||||||
import Alert from '../../alert/Alert';
|
import Alert from '../../alert/Alert';
|
||||||
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
|
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
|
import { Skill } from '../skills/Skill.interface';
|
||||||
|
|
||||||
interface ActionsProps {
|
interface ActionsProps {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -169,6 +154,17 @@ const Projects = () => {
|
|||||||
accessorKey: 'summary',
|
accessorKey: 'summary',
|
||||||
header: 'Summary'
|
header: 'Summary'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'skills',
|
||||||
|
accessorKey: 'skills',
|
||||||
|
header: 'Skills',
|
||||||
|
cell: (info: CellContext<Project, unknown>) => {
|
||||||
|
const skills = info.getValue() as Skill[];
|
||||||
|
const skillsString: string = skills.map((skill) => skill.name).join(', ')
|
||||||
|
|
||||||
|
return skillsString
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'status',
|
id: 'status',
|
||||||
accessorKey: 'status',
|
accessorKey: 'status',
|
||||||
|
|||||||
BIN
database/portfolio.db
Normal file
BIN
database/portfolio.db
Normal file
Binary file not shown.
70
docker-compose.yaml
Normal file
70
docker-compose.yaml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
services:
|
||||||
|
azurite:
|
||||||
|
container_name: azurite-portfolio
|
||||||
|
image: mcr.microsoft.com/azure-storage/azurite
|
||||||
|
ports:
|
||||||
|
- '10000:10000'
|
||||||
|
- '10001:10001'
|
||||||
|
- '10002:10002'
|
||||||
|
command: 'azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --loose --skipApiVersionCheck'
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "nc", "-z", "127.0.0.1", "10000"]
|
||||||
|
volumes:
|
||||||
|
- ./azurite-data:/data
|
||||||
|
|
||||||
|
# seed:
|
||||||
|
# image: mcr.microsoft.com/azure-cli
|
||||||
|
# depends_on:
|
||||||
|
# azurite:
|
||||||
|
# condition: service_healthy
|
||||||
|
# volumes:
|
||||||
|
# - ./seed-data:/data
|
||||||
|
# entrypoint: >
|
||||||
|
# sh -c "
|
||||||
|
# az storage container create --name mycontainer --connection-string 'DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;' &&
|
||||||
|
# az storage blob upload-batch --destination mycontainer --source /data --connection-string 'DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;'
|
||||||
|
# "
|
||||||
|
|
||||||
|
restore:
|
||||||
|
container_name: restore
|
||||||
|
image: litestream/litestream:0.5.2
|
||||||
|
volumes:
|
||||||
|
- ./database/portfolio.db:/mnt/data/portfolio.db
|
||||||
|
- ./database/litestream/litestream.yml:/mnt/litestream/litestream.yml
|
||||||
|
- backup:/mnt/data/backup
|
||||||
|
- data:/mnt/data
|
||||||
|
command: restore -config /mnt/litestream/litestream.yml -if-db-not-exists -if-replica-exists /mnt/data/portfolio.db
|
||||||
|
|
||||||
|
app:
|
||||||
|
container_name: portfolio
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
ports:
|
||||||
|
- '3000:3000'
|
||||||
|
env_file:
|
||||||
|
- ./api/.env
|
||||||
|
environment:
|
||||||
|
- DB_PATH=../../mnt/data/portfolio.db
|
||||||
|
volumes:
|
||||||
|
- data:/mnt/data
|
||||||
|
depends_on:
|
||||||
|
restore:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
|
||||||
|
replicate:
|
||||||
|
container_name: replicate
|
||||||
|
image: litestream/litestream:0.5.2
|
||||||
|
volumes:
|
||||||
|
- ./database/litestream/litestream.yml:/mnt/litestream/litestream.yml
|
||||||
|
- backup:/mnt
|
||||||
|
- data:/mnt/data
|
||||||
|
command: replicate -config /mnt/litestream/litestream.yml
|
||||||
|
depends_on:
|
||||||
|
app:
|
||||||
|
condition: service_started
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
azurite-data:
|
||||||
|
backup:
|
||||||
|
data:
|
||||||
|
# seed-data:
|
||||||
14535
package-lock.json
generated
Normal file
14535
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"api",
|
"api",
|
||||||
"cms",
|
"client",
|
||||||
"static-wfe"
|
"static-wfe"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user