Skip to content

Commit

Permalink
[Feature] Training opportunity admin CRUD pages (#12067)
Browse files Browse the repository at this point in the history
* index and create started

* view and update started

* add form fields

* index table wip

* view event page data

* update page

* create page

* fragment form options

* fix intl strings

* undo formatting

* add api wrapper for view page

* fix table sorting bug

* lint

* better label and move language

* rename files

* event -> opportunity

* registration -> application

* translations

* update duplicate string snapshot

* date validation rules
  • Loading branch information
petertgiles authored Nov 22, 2024
1 parent 5acaadd commit 5bd7bf6
Show file tree
Hide file tree
Showing 24 changed files with 1,738 additions and 10 deletions.
18 changes: 18 additions & 0 deletions api/app/Enums/DeadlineStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace App\Enums;

use App\Traits\HasLocalization;

enum DeadlineStatus
{
use HasLocalization;

case PUBLISHED;
case EXPIRED;

public static function getLangFilename(): string
{
return 'deadline_status';
}
}
18 changes: 18 additions & 0 deletions api/app/Models/TrainingOpportunity.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
namespace App\Models;

use App\Enums\CourseLanguage;
use App\Enums\DeadlineStatus;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

Expand Down Expand Up @@ -52,6 +54,7 @@ public static function scopeHidePassedRegistrationDeadline(Builder $query, ?bool
{
// if true only display where registration deadline is in the future
if (isset($filterBool) && $filterBool) {
// this should match the logic in registrationDeadlineStatus
$query->where(function ($query) {
$query->whereDate('registration_deadline', '>=', date('Y-m-d'))
->orWhereNull('registration_deadline');
Expand All @@ -70,4 +73,19 @@ public static function scopeOpportunityLanguage(Builder $query, ?string $languag

return $query;
}

/**
* Get the registration deadline status with respect to the current date
*/
protected function registrationDeadlineStatus(): Attribute
{
/** @disregard P1003 Not using value parameter */
return Attribute::make(
// this should match the logic in scopeHidePassedRegistrationDeadline
get: fn (mixed $value, array $attributes) => $attributes['registration_deadline'] >= date('Y-m-d') || is_null($attributes['registration_deadline'])
? DeadlineStatus::PUBLISHED->name
: DeadlineStatus::EXPIRED->name

);
}
}
2 changes: 2 additions & 0 deletions api/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,7 @@ type TrainingOpportunity {
title: LocalizedString
courseLanguage: LocalizedCourseLanguage @rename(attribute: "course_language")
registrationDeadline: Date @rename(attribute: "registration_deadline")
registrationDeadlineStatus: LocalizedDeadlineStatus
trainingStart: Date @rename(attribute: "training_start")
trainingEnd: Date @rename(attribute: "training_end")
description: LocalizedString
Expand Down Expand Up @@ -1094,6 +1095,7 @@ type Query {
trainingOpportunity(id: UUID! @eq): TrainingOpportunity @find
trainingOpportunitiesPaginated(
where: TrainingOpportunitiesFilterInput
orderBy: [OrderByClause!] @orderBy
): [TrainingOpportunity]
@paginate(
defaultCount: 10
Expand Down
6 changes: 6 additions & 0 deletions api/lang/en/deadline_status.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

return [
'published' => 'Published',
'expired' => 'Expired',
];
6 changes: 6 additions & 0 deletions api/lang/fr/deadline_status.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

return [
'published' => 'Publié',
'expired' => 'Expiré',
];
12 changes: 12 additions & 0 deletions api/storage/app/lighthouse-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ type LocalizedCourseLanguage {
label: LocalizedString!
}

type LocalizedDeadlineStatus {
value: DeadlineStatus!
label: LocalizedString!
}

type LocalizedEducationRequirementOption {
value: EducationRequirementOption!
label: LocalizedString!
Expand Down Expand Up @@ -332,6 +337,7 @@ type Query {
): NotificationPaginator!
trainingOpportunitiesPaginated(
where: TrainingOpportunitiesFilterInput
orderBy: [OrderByClause!]

"Limits number of fetched items. Maximum allowed value: 1000."
first: Int! = 10
Expand Down Expand Up @@ -1211,6 +1217,7 @@ type TrainingOpportunity {
title: LocalizedString
courseLanguage: LocalizedCourseLanguage
registrationDeadline: Date
registrationDeadlineStatus: LocalizedDeadlineStatus
trainingStart: Date
trainingEnd: Date
description: LocalizedString
Expand Down Expand Up @@ -2695,6 +2702,11 @@ enum CourseLanguage {
BILINGUAL
}

enum DeadlineStatus {
PUBLISHED
EXPIRED
}

enum AdvertisementType {
INTERNAL
EXTERNAL
Expand Down
38 changes: 38 additions & 0 deletions apps/web/src/components/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,44 @@ const createRoute = (locale: Locales) =>
},
],
},
{
path: "training-opportunities",
children: [
{
index: true,
lazy: () =>
import(
"../pages/TrainingOpportunities/IndexTrainingOpportunitiesPage"
),
},
{
path: "create",
lazy: () =>
import(
"../pages/TrainingOpportunities/CreateTrainingOpportunityPage"
),
},
{
path: ":trainingOpportunityId",
children: [
{
index: true,
lazy: () =>
import(
"../pages/TrainingOpportunities/ViewTrainingOpportunityPage"
),
},
{
path: "edit",
lazy: () =>
import(
"../pages/TrainingOpportunities/UpdateTrainingOpportunityPage"
),
},
],
},
],
},
{
path: "settings",
children: [
Expand Down
12 changes: 12 additions & 0 deletions apps/web/src/hooks/useRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,18 @@ const getRoutes = (lang: Locales) => {
// IT Training Fund
itTrainingFund: () => [baseUrl, "it-training-fund"].join("/"),

// Training Opportunities (Admin)
trainingOpportunitiesIndex: () =>
[adminUrl, "training-opportunities"].join("/"),
trainingOpportunityCreate: () =>
[adminUrl, "training-opportunities", "create"].join("/"),
trainingOpportunityView: (trainingOpportunityId: string) =>
[adminUrl, "training-opportunities", trainingOpportunityId].join("/"),
trainingOpportunityUpdate: (trainingOpportunityId: string) =>
[adminUrl, "training-opportunities", trainingOpportunityId, "edit"].join(
"/",
),

/**
* Deprecated
*
Expand Down
7 changes: 7 additions & 0 deletions apps/web/src/lang/__snapshots__/lang.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ exports[`message files should have no changes to duplicate strings 1`] = `
"Ajoutez un rôle dans l'équipe"
]
},
{
"en": "Create a training opportunity",
"fr": [
"Créez une possibilité de formation",
"Créer une possibilité de formation"
]
},
{
"en": "Add process role",
"fr": [
Expand Down
Loading

0 comments on commit 5bd7bf6

Please sign in to comment.