diff --git a/client/src/api/api.ts b/client/src/api/api.ts index b37c6dc4e..9a25e5450 100644 --- a/client/src/api/api.ts +++ b/client/src/api/api.ts @@ -1030,6 +1030,18 @@ export interface CourseDto { * @memberof CourseDto */ 'personalMentoring': boolean; + /** + * + * @type {string} + * @memberof CourseDto + */ + 'personalMentoringStartDate': string | null; + /** + * + * @type {string} + * @memberof CourseDto + */ + 'personalMentoringEndDate': string | null; /** * * @type {string} @@ -1925,6 +1937,18 @@ export interface CreateCourseDto { * @memberof CreateCourseDto */ 'personalMentoring'?: boolean; + /** + * + * @type {string} + * @memberof CreateCourseDto + */ + 'personalMentoringStartDate'?: string; + /** + * + * @type {string} + * @memberof CreateCourseDto + */ + 'personalMentoringEndDate'?: string; /** * * @type {string} @@ -4806,6 +4830,18 @@ export interface ProfileCourseDto { * @memberof ProfileCourseDto */ 'personalMentoring': boolean; + /** + * + * @type {string} + * @memberof ProfileCourseDto + */ + 'personalMentoringStartDate': string | null; + /** + * + * @type {string} + * @memberof ProfileCourseDto + */ + 'personalMentoringEndDate': string | null; /** * * @type {string} @@ -6609,6 +6645,18 @@ export interface UpdateCourseDto { * @memberof UpdateCourseDto */ 'personalMentoring'?: boolean; + /** + * + * @type {string} + * @memberof UpdateCourseDto + */ + 'personalMentoringStartDate'?: string | null; + /** + * + * @type {string} + * @memberof UpdateCourseDto + */ + 'personalMentoringEndDate'?: string | null; /** * * @type {string} diff --git a/client/src/modules/CourseManagement/components/CourseModal/index.tsx b/client/src/modules/CourseManagement/components/CourseModal/index.tsx index 25f163d50..fdad1be66 100644 --- a/client/src/modules/CourseManagement/components/CourseModal/index.tsx +++ b/client/src/modules/CourseManagement/components/CourseModal/index.tsx @@ -45,6 +45,9 @@ type FormData = { logo?: string; usePrivateRepositories?: boolean; personalMentoring?: boolean; + personalMentoringStartDate?: string | null; + personalMentoringEndDate?: string | null; + personalMentoringDateRange: [dayjs.Dayjs | null, dayjs.Dayjs | null] | null; certificateIssuer?: string; discipline?: { id: number } | null; courseId?: number; @@ -308,9 +311,28 @@ export function CourseModal(props: CourseModalProps) { Use Private Repositories - - Personal mentoring - + + + + Personal mentoring + + + + + {({ getFieldValue }) => + getFieldValue('personalMentoring') ? ( + + + + ) : null + } + + + Invite Only Course @@ -323,6 +345,10 @@ export function CourseModal(props: CourseModalProps) { function createRecord(values: FormData) { const [startDate, endDate] = values.range as [dayjs.Dayjs, dayjs.Dayjs]; + const [personalMentoringStartDate, personalMentoringEndDate] = values.personalMentoringDateRange + ? (values.personalMentoringDateRange as [dayjs.Dayjs, dayjs.Dayjs]) + : [null, null]; + const record: UpdateCourseDto = { name: values.name, fullName: values.fullName, @@ -339,6 +365,12 @@ function createRecord(values: FormData) { discordServerId: values.discordServerId, usePrivateRepositories: values.usePrivateRepositories, personalMentoring: values.personalMentoring, + personalMentoringStartDate: personalMentoringStartDate + ? dayjs.utc(personalMentoringStartDate).startOf('day').format() + : null, + personalMentoringEndDate: personalMentoringEndDate + ? dayjs.utc(personalMentoringEndDate).startOf('day').format() + : null, logo: values.logo, minStudentsPerMentor: values.minStudentsPerMentor, certificateThreshold: values.certificateThreshold, @@ -347,7 +379,17 @@ function createRecord(values: FormData) { return record; } +function getDateRange( + startDate?: string | null, + endDate?: string | null, +): [dayjs.Dayjs | null, dayjs.Dayjs | null] | null { + return startDate && endDate ? [startDate ? dayjs.utc(startDate) : null, endDate ? dayjs.utc(endDate) : null] : null; +} + function getInitialValues(modalData: Partial): FormData { + const range = getDateRange(modalData.startDate, modalData.endDate); + const personalMentoringDateRange = + getDateRange(modalData.personalMentoringStartDate, modalData.personalMentoringEndDate) || range; return { ...modalData, wearecommunityUrl: modalData.wearecommunityUrl ?? undefined, @@ -356,12 +398,7 @@ function getInitialValues(modalData: Partial): FormData { inviteOnly: !!modalData.inviteOnly, state: modalData.completed ? 'completed' : modalData.planned ? 'planned' : 'active', registrationEndDate: modalData.registrationEndDate ? dayjs.utc(modalData.registrationEndDate) : null, - range: - modalData.startDate && modalData.endDate - ? [ - modalData.startDate ? dayjs.utc(modalData.startDate) : null, - modalData.endDate ? dayjs.utc(modalData.endDate) : null, - ] - : null, + range: range, + personalMentoringDateRange: personalMentoringDateRange, }; } diff --git a/nestjs/src/courses/dto/course.dto.ts b/nestjs/src/courses/dto/course.dto.ts index 7fb305e62..93c3e9f54 100644 --- a/nestjs/src/courses/dto/course.dto.ts +++ b/nestjs/src/courses/dto/course.dto.ts @@ -23,6 +23,8 @@ export class CourseDto { this.usePrivateRepositories = course.usePrivateRepositories; this.registrationEndDate = course.registrationEndDate?.toISOString() ?? null; this.personalMentoring = course.personalMentoring; + this.personalMentoringStartDate = course.personalMentoringStartDate?.toISOString() ?? null; + this.personalMentoringEndDate = course.personalMentoringEndDate?.toISOString() ?? null; this.logo = course.logo; this.discipline = course.discipline ? { id: course.discipline.id, name: course.discipline.name } : null; this.minStudentsPerMentor = course.minStudentsPerMentor; @@ -96,6 +98,12 @@ export class CourseDto { @ApiProperty() personalMentoring: boolean; + @ApiProperty({ type: 'string', nullable: true }) + personalMentoringStartDate: string | null; + + @ApiProperty({ type: 'string', nullable: true }) + personalMentoringEndDate: string | null; + @ApiProperty() logo: string; diff --git a/nestjs/src/courses/dto/create-course.dto.ts b/nestjs/src/courses/dto/create-course.dto.ts index 5cd255e82..638615587 100644 --- a/nestjs/src/courses/dto/create-course.dto.ts +++ b/nestjs/src/courses/dto/create-course.dto.ts @@ -77,6 +77,16 @@ export class CreateCourseDto { @ApiProperty({ required: false }) personalMentoring?: boolean; + @IsString() + @IsOptional() + @ApiProperty({ required: false }) + personalMentoringStartDate?: string; + + @IsString() + @IsOptional() + @ApiProperty({ required: false }) + personalMentoringEndDate?: string; + @IsString() @IsOptional() @ApiProperty({ required: false }) diff --git a/nestjs/src/courses/dto/export-course.dto.ts b/nestjs/src/courses/dto/export-course.dto.ts index 21db47458..93433e643 100644 --- a/nestjs/src/courses/dto/export-course.dto.ts +++ b/nestjs/src/courses/dto/export-course.dto.ts @@ -12,6 +12,8 @@ export class ExportCourseDto { this.description = course.description; this.descriptionUrl = course.descriptionUrl; this.registrationEndDate = course.registrationEndDate?.toISOString() ?? null; + this.personalMentoringStateDate = course.personalMentoringStartDate?.toISOString() ?? null; + this.personalMentoringEndDate = course.personalMentoringEndDate?.toISOString() ?? null; this.wearecommunityUrl = course.wearecommunityUrl || null; } @@ -25,5 +27,7 @@ export class ExportCourseDto { registrationEndDate: string | null; startDate: string; endDate: string; + personalMentoringStateDate: string | null; + personalMentoringEndDate: string | null; wearecommunityUrl: string | null; } diff --git a/nestjs/src/courses/dto/update-course.dto.ts b/nestjs/src/courses/dto/update-course.dto.ts index 50473881e..9b8ab4370 100644 --- a/nestjs/src/courses/dto/update-course.dto.ts +++ b/nestjs/src/courses/dto/update-course.dto.ts @@ -82,6 +82,16 @@ export class UpdateCourseDto { @ApiPropertyOptional() personalMentoring?: boolean; + @IsString() + @IsOptional() + @ApiPropertyOptional({ type: 'string', nullable: true }) + personalMentoringStartDate?: string | null; + + @IsString() + @IsOptional() + @ApiPropertyOptional({ type: 'string', nullable: true }) + personalMentoringEndDate?: string | null; + @IsString() @IsOptional() @ApiPropertyOptional() diff --git a/nestjs/src/spec.json b/nestjs/src/spec.json index e257ef85f..a49c69f57 100644 --- a/nestjs/src/spec.json +++ b/nestjs/src/spec.json @@ -2940,6 +2940,8 @@ "certificateIssuer": { "type": "string" }, "usePrivateRepositories": { "type": "boolean" }, "personalMentoring": { "type": "boolean" }, + "personalMentoringStartDate": { "type": "string", "nullable": true }, + "personalMentoringEndDate": { "type": "string", "nullable": true }, "logo": { "type": "string" }, "discipline": { "nullable": true, "allOf": [{ "$ref": "#/components/schemas/IdNameDto" }] }, "minStudentsPerMentor": { "type": "number" }, @@ -2969,6 +2971,8 @@ "certificateIssuer", "usePrivateRepositories", "personalMentoring", + "personalMentoringStartDate", + "personalMentoringEndDate", "logo", "discipline", "minStudentsPerMentor", @@ -2995,6 +2999,8 @@ "usePrivateRepositories": { "type": "boolean" }, "certificateIssuer": { "type": "string" }, "personalMentoring": { "type": "boolean" }, + "personalMentoringStartDate": { "type": "string" }, + "personalMentoringEndDate": { "type": "string" }, "logo": { "type": "string" }, "minStudentsPerMentor": { "type": "number" }, "certificateThreshold": { "type": "number" }, @@ -3022,6 +3028,8 @@ "certificateIssuer": { "type": "string" }, "usePrivateRepositories": { "type": "boolean" }, "personalMentoring": { "type": "boolean" }, + "personalMentoringStartDate": { "type": "string", "nullable": true }, + "personalMentoringEndDate": { "type": "string", "nullable": true }, "logo": { "type": "string" }, "disciplineId": { "type": "number" }, "minStudentsPerMentor": { "type": "number" }, @@ -4443,6 +4451,8 @@ "certificateIssuer": { "type": "string" }, "usePrivateRepositories": { "type": "boolean" }, "personalMentoring": { "type": "boolean" }, + "personalMentoringStartDate": { "type": "string", "nullable": true }, + "personalMentoringEndDate": { "type": "string", "nullable": true }, "logo": { "type": "string" }, "discipline": { "nullable": true, "allOf": [{ "$ref": "#/components/schemas/IdNameDto" }] }, "minStudentsPerMentor": { "type": "number" }, @@ -4472,6 +4482,8 @@ "certificateIssuer", "usePrivateRepositories", "personalMentoring", + "personalMentoringStartDate", + "personalMentoringEndDate", "logo", "discipline", "minStudentsPerMentor", diff --git a/server/src/migrations/1738250779923-CoursePersonalMentoringDates.ts b/server/src/migrations/1738250779923-CoursePersonalMentoringDates.ts new file mode 100644 index 000000000..a7fc68647 --- /dev/null +++ b/server/src/migrations/1738250779923-CoursePersonalMentoringDates.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class CoursePersonalMentoringDates1738250779923 implements MigrationInterface { + name = 'CoursePersonalMentoringDates1738250779923'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "course" ADD "personalMentoringStartDate" TIMESTAMP WITH TIME ZONE`); + await queryRunner.query(`ALTER TABLE "course" ADD "personalMentoringEndDate" TIMESTAMP WITH TIME ZONE`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "course" DROP COLUMN "personalMentoringStartDate"`); + await queryRunner.query(`ALTER TABLE "course" DROP COLUMN "personalMentoringEndDate"`); + } +} diff --git a/server/src/migrations/index.ts b/server/src/migrations/index.ts index d163faf6c..894eaf17d 100644 --- a/server/src/migrations/index.ts +++ b/server/src/migrations/index.ts @@ -58,6 +58,7 @@ import { Course1712137476312 } from './1712137476312-Course'; import { CourseTask1730926720293 } from './1730926720293-CourseTask'; import { Contributor1734874453585 } from './1734874453585-Contributor'; import { Course1736458672717 } from './1736458672717-Course'; +import { CoursePersonalMentoringDates1738250779923 } from './1738250779923-CoursePersonalMentoringDates'; export const migrations = [ UserMigration1630340371992, @@ -120,4 +121,5 @@ export const migrations = [ CourseTask1730926720293, Contributor1734874453585, Course1736458672717, + CoursePersonalMentoringDates1738250779923, ]; diff --git a/server/src/models/course.ts b/server/src/models/course.ts index 82ced6447..4977a2a5d 100644 --- a/server/src/models/course.ts +++ b/server/src/models/course.ts @@ -96,6 +96,12 @@ export class Course { @Column({ default: true }) personalMentoring: boolean; + @Column({ type: 'timestamptz', nullable: true }) + personalMentoringStartDate: Date | null; + + @Column({ type: 'timestamptz', nullable: true }) + personalMentoringEndDate: Date | null; + @Column({ nullable: true }) logo: string; diff --git a/setup/backup-local.sql b/setup/backup-local.sql index 87c5db991..732dccb88 100644 --- a/setup/backup-local.sql +++ b/setup/backup-local.sql @@ -3,7 +3,7 @@ -- -- Dumped from database version 15.5 (Debian 15.5-1.pgdg120+1) --- Dumped by pg_dump version 15.10 (Homebrew) +-- Dumped by pg_dump version 15.10 SET statement_timeout = 0; SET lock_timeout = 0; @@ -250,7 +250,9 @@ CREATE TABLE public.course ( "disciplineId" integer, "minStudentsPerMentor" integer DEFAULT 2, "certificateThreshold" integer DEFAULT 70 NOT NULL, - "wearecommunityUrl" character varying + "wearecommunityUrl" character varying, + "personalMentoringStartDate" timestamp with time zone, + "personalMentoringEndDate" timestamp with time zone ); @@ -2603,10 +2605,10 @@ COPY public.contributor (id, created_date, updated_date, deleted_date, user_id, -- Data for Name: course; Type: TABLE DATA; Schema: public; Owner: rs_master -- -COPY public.course (id, "createdDate", "updatedDate", name, year, "primarySkillId", "primarySkillName", "locationName", alias, completed, description, "descriptionUrl", planned, "startDate", "endDate", "fullName", "registrationEndDate", "inviteOnly", "discordServerId", "certificateIssuer", "usePrivateRepositories", "personalMentoring", logo, "disciplineId", "minStudentsPerMentor", "certificateThreshold", "wearecommunityUrl") FROM stdin; -11 2019-08-27 07:36:13.565873 2020-03-13 15:39:41.477995 RS 2019 Q3 \N javascript JavaScript \N rs-2019-q3 t RS 2019 Q3 \N f 2019-09-09 07:35:20.981+00 2020-01-31 07:35:20.981+00 Rolling Scopes School 2019 Q3 \N f \N \N t t \N \N 2 70 \N -13 2019-10-21 08:05:31.068833 2020-04-06 15:14:44.116961 RS 2020 Q1 \N javascript JavaScript \N rs-2020-q1 f Javascript / Frontend Курс.\nВводное занятие - 2 февраля\nОрганизационный вебинар начнется 2 февраля в 12:00 по минскому времени (GMT+3). Мы расскажем о процессе обучения в RS School и выдадим задания для первого этапа обучения.\n\nВебинар будет транслироваться на канале https://www.youtube.com/c/rollingscopesschool.\nРекомендуем подписаться на канал и нажать колокольчик, чтобы не пропустить начало трансляции. \n\nЕсли у вас не будет возможности присоединиться к онлайн-трансляции, не переживайте! \nЗапись вебинара будет размещена на канале в открытом доступе.\n\nОписание тренинга\nОсновной сайт: https://rs.school/js/\n\nПодробная информация о школе: https://docs.rs.school \N f 2020-02-02 09:01:56.398+00 2020-07-31 08:01:56.398+00 Rolling Scopes School 2020 Q1: JavaScript/Front-end 2020-04-15 08:40:46.24+00 f \N \N t t \N \N 2 70 \N -23 2020-02-25 09:28:08.842897 2021-07-28 20:44:30.259905 TEST COURSE \N javascript JavaScript \N test-course f TEST COURSE \N f 2021-05-31 21:00:00+00 2023-06-30 21:00:00+00 TEST COURSE \N t 2 \N t t \N \N 2 70 \N +COPY public.course (id, "createdDate", "updatedDate", name, year, "primarySkillId", "primarySkillName", "locationName", alias, completed, description, "descriptionUrl", planned, "startDate", "endDate", "fullName", "registrationEndDate", "inviteOnly", "discordServerId", "certificateIssuer", "usePrivateRepositories", "personalMentoring", logo, "disciplineId", "minStudentsPerMentor", "certificateThreshold", "wearecommunityUrl", "personalMentoringStartDate", "personalMentoringEndDate") FROM stdin; +13 2019-10-21 08:05:31.068833 2020-04-06 15:14:44.116961 RS 2020 Q1 \N javascript JavaScript \N rs-2020-q1 f Javascript / Frontend Курс.\nВводное занятие - 2 февраля\nОрганизационный вебинар начнется 2 февраля в 12:00 по минскому времени (GMT+3). Мы расскажем о процессе обучения в RS School и выдадим задания для первого этапа обучения.\n\nВебинар будет транслироваться на канале https://www.youtube.com/c/rollingscopesschool.\nРекомендуем подписаться на канал и нажать колокольчик, чтобы не пропустить начало трансляции. \n\nЕсли у вас не будет возможности присоединиться к онлайн-трансляции, не переживайте! \nЗапись вебинара будет размещена на канале в открытом доступе.\n\nОписание тренинга\nОсновной сайт: https://rs.school/js/\n\nПодробная информация о школе: https://docs.rs.school \N f 2020-02-02 09:01:56.398+00 2020-07-31 08:01:56.398+00 Rolling Scopes School 2020 Q1: JavaScript/Front-end 2020-04-15 08:40:46.24+00 f \N \N t t \N \N 2 70 \N \N \N +23 2020-02-25 09:28:08.842897 2021-07-28 20:44:30.259905 TEST COURSE \N javascript JavaScript \N test-course f TEST COURSE \N f 2021-05-31 21:00:00+00 2023-06-30 21:00:00+00 TEST COURSE \N t 2 \N t t \N \N 2 70 \N \N \N +11 2019-08-27 07:36:13.565873 2025-01-30 19:25:33.198749 RS 2019 Q3 \N javascript JavaScript \N rs-2019-q3 t RS 2019 Q3 https://rs.school/courses/javascript-preschool-ru f 2019-09-09 00:00:00+00 2020-01-31 00:00:00+00 Rolling Scopes School 2019 Q3 \N f 2 \N t t \N 1 2 70 \N 2019-09-23 00:00:00+00 2020-01-31 00:00:00+00 \. @@ -3317,6 +3319,7 @@ COPY public.migrations (id, "timestamp", name) FROM stdin; 58 1730926720293 CourseTask1730926720293 59 1734874453585 Contributor1734874453585 60 1736458672717 Course1736458672717 +61 1738250779923 CoursePersonalMentoringDates1738250779923 \. @@ -4250,7 +4253,7 @@ SELECT pg_catalog.setval('public.mentor_registry_id_seq', 290, true); -- Name: migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: rs_master -- -SELECT pg_catalog.setval('public.migrations_id_seq', 60, true); +SELECT pg_catalog.setval('public.migrations_id_seq', 61, true); --