Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
7349187
Split Case Study editing into multiple edit pages with subnavigation
dave-mills Sep 3, 2025
7b7202e
teams table seeder file, remove attribute for avatar column (this col…
dan-tang-ssd Sep 4, 2025
25cc430
to make it working properly after creating a new study case in tab pa…
dan-tang-ssd Sep 4, 2025
af18387
Merge pull request #110 from stats4sd/fix-setup-script
dan-tang-ssd Sep 4, 2025
bd7ddb8
recover ClaimsRelationManager as we need it to manage Claims and Evid…
dan-tang-ssd Sep 4, 2025
3358528
update the route for editing claims and evidence
dan-tang-ssd Sep 4, 2025
e872aaa
re-show Edit button in Claims and Evidence page
dan-tang-ssd Sep 4, 2025
6252389
fix navigation issue
dan-tang-ssd Sep 4, 2025
964717e
add Save changes button at top of page
dan-tang-ssd Sep 4, 2025
8b44d90
Admin panel, change color from yellow to red
dan-tang-ssd Sep 4, 2025
85d196a
app panel, remove Partner Organisations from sidebar; app panel, chan…
dan-tang-ssd Sep 4, 2025
6f2ba6a
Merge pull request #112 from stats4sd/revise-admin-panel-app-panel
dan-tang-ssd Sep 4, 2025
2024ee7
apply app panel StudyCaseResource structural changes to admin panel S…
dan-tang-ssd Sep 4, 2025
eac9d7f
redirect to edit basic information page after creating a study case r…
dan-tang-ssd Sep 4, 2025
f630675
Merge pull request #111 from stats4sd/split-edit-pages
dan-tang-ssd Sep 4, 2025
6533349
add column study_cases.status; add Enum class StudyCaseStatus; add on…
dan-tang-ssd Sep 5, 2025
0814952
update study case status label; hide columns study_cases.ready_for_re…
dan-tang-ssd Sep 5, 2025
d679b09
WIP: add confirmation page to show possible action to be taken for di…
dan-tang-ssd Sep 5, 2025
e6eccf9
revert Confirmation page, show the corresponding section per status p…
dan-tang-ssd Sep 8, 2025
fda4224
Admin panel > StudyCaseResource, add EditConfirmation page
dan-tang-ssd Sep 8, 2025
4b81ff5
install spatie ray package
dan-tang-ssd Sep 8, 2025
b67bd19
add header actions to update study case status
dan-tang-ssd Sep 8, 2025
882cd2e
Merge pull request #113 from stats4sd/add_study_case_status
dan-tang-ssd Sep 8, 2025
68fcc4e
newly created study case should have status Proposal
dan-tang-ssd Sep 8, 2025
cde02f7
for Proposal stage cases, hide leading organisation and partner orgs …
dan-tang-ssd Sep 8, 2025
bfe0755
remove status Ready for Development and related code; add status Closed
dan-tang-ssd Sep 8, 2025
d2e8632
StudyCaseResurce, add code for Further Develop and Close
dan-tang-ssd Sep 8, 2025
3404ec1
admin panel StudyCaseResource, fix to use admin panel StudyCaseResour…
dan-tang-ssd Sep 9, 2025
d1a9b78
admin panel StudyCaseResource, revise filter for status
dan-tang-ssd Sep 9, 2025
4d2dd8c
admin panel StudyCaseResource, apply default filter to hide study cas…
dan-tang-ssd Sep 9, 2025
91d422f
Change navigation based on case study's status
dave-mills Sep 9, 2025
37d153c
Merge pull request #114 from stats4sd/study-case-editing
dan-tang-ssd Sep 9, 2025
1d71f20
study case Preview page, do not show leading organisation contact per…
dan-tang-ssd Sep 10, 2025
1672e85
add StudyCasePolicy for testing, check if Preview function trigger it
dan-tang-ssd Sep 10, 2025
8251a6c
remove StudyCasePolicy as Preview function does not trigger it
dan-tang-ssd Sep 10, 2025
84d57ee
add Preview page access control in StudyCaseController
dan-tang-ssd Sep 10, 2025
48c79b2
change error 403 to error 404
dan-tang-ssd Sep 10, 2025
036c0e3
trying to use StudyCasePolicy...
dan-tang-ssd Sep 10, 2025
68f6410
move access control business logic to StudyCasePolicy
dan-tang-ssd Sep 11, 2025
cb64027
revise comment and remove unused code
dan-tang-ssd Sep 11, 2025
09f1d81
Merge pull request #115 from stats4sd/add-access-control
dan-tang-ssd Sep 11, 2025
b4dec81
enable filament sign up feature in app panel; add custom register cla…
dan-tang-ssd Sep 12, 2025
cd8e769
add app panel Teams resource, show users and invites; allow user to s…
dan-tang-ssd Sep 12, 2025
2c2109e
minor bug fix
dan-tang-ssd Sep 12, 2025
79f8b83
bug fix to show Confirmation tab page for admin regardless of study c…
dan-tang-ssd Sep 15, 2025
e1d08c8
add a new page Create Your Case in front-end
dan-tang-ssd Sep 15, 2025
21c61bc
revise Create Your Case page in front-end
dan-tang-ssd Sep 15, 2025
a769019
app panel > study case resources > list page, add a description box t…
dan-tang-ssd Sep 15, 2025
70e9315
app panel and admin panel, study case resources > move Claims and Evi…
dan-tang-ssd Sep 15, 2025
86bafc7
admin panel > Study case resource, list view, Edit button, divert to …
dan-tang-ssd Sep 15, 2025
c4e0528
app panel > Study case resource > create page > edit basic informatio…
dan-tang-ssd Sep 15, 2025
fc493aa
register new user page, revise to accept a pre-defined Course Code fo…
dan-tang-ssd Sep 15, 2025
be96d9e
attempt to enable the Laravel / Filament email verification feature b…
dan-tang-ssd Sep 15, 2025
d1eebed
Study case resource > confirmation page > simplify messages to avoid …
dan-tang-ssd Sep 15, 2025
fd36055
re-enable MustVerifyEmail
dave-mills Sep 15, 2025
ff81a0f
Add 'view' mode for Basic Information page
dave-mills Sep 15, 2025
7cbd631
Add 'view' mode for Basic Information page; Add custom create action;
dave-mills Sep 15, 2025
f8e15b0
composer updates to fix 'depreciated' notice
dave-mills Sep 15, 2025
e7dec85
remove unncessary comment
dan-tang-ssd Sep 16, 2025
0a92548
fill in default values after creating a new study case
dan-tang-ssd Sep 16, 2025
172e042
add View version of other Edit pages; update StudyCaseRecource::getRe…
dan-tang-ssd Sep 16, 2025
05cfcd4
add View version to admin panel > StudyCase resource
dan-tang-ssd Sep 16, 2025
503a849
WIP: trying to change a relation manager from Edit mode to View mode
dan-tang-ssd Sep 16, 2025
f14578a
Edit pages, add getRedirectUrl() function to redirect to next Edit pa…
dan-tang-ssd Sep 16, 2025
8331c9e
remove testing code for isReadOnly(); copy ManageCaseStudyClaims as V…
dan-tang-ssd Sep 16, 2025
4ca10c7
Merge pull request #116 from stats4sd/add-user-registration-and-user-…
dan-tang-ssd Sep 17, 2025
79f480c
Cases resource > list page, change hardcoded strings to translatable …
dan-tang-ssd Sep 22, 2025
b12036c
fix typo; change geographical area from compulsory to optional
dan-tang-ssd Sep 22, 2025
9c676bd
Merge pull request #117 from stats4sd/add-internal-user-feedback
dan-tang-ssd Sep 22, 2025
acd5f1d
fix the unfixed typo; fill in missing function trimUrlContent()
dan-tang-ssd Sep 22, 2025
91516e6
Merge pull request #118 from stats4sd/add-internal-user-feedback-2
dan-tang-ssd Sep 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_TIMEZONE=UTC
APP_URL=http://localhost
APP_URL=http://aef.test

APP_LOCALE=en
APP_FALLBACK_LOCALE=en
Expand Down
53 changes: 53 additions & 0 deletions app/Console/Commands/FillStudyCaseStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace App\Console\Commands;

use App\Models\StudyCase;
use App\Enums\StudyCaseStatus;
use Illuminate\Console\Command;

class FillStudyCaseStatus extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:fill-study-case-status';

/**
* The console command description.
*
* @var string
*/
protected $description = 'A one-time command program to fill study case status';

/**
* Execute the console command.
*/
public function handle()
{
$this->info('start');

$studyCases = StudyCase::all();

foreach ($studyCases as $studyCase) {
if ($studyCase->reviewed) {
$studyCase->status = StudyCaseStatus::Reviewed;
} else if ($studyCase->ready_for_review) {
$studyCase->status = StudyCaseStatus::ReadyForReview;
} else {
// Question: for existing study cases not yet ready for review, should we consider them as Proposal or Development?
// Proposal means the study case creator does not ask for reviewer's approval
// Development means the creator has asked reviewer for approval, and the reviewer has approved this study case

$studyCase->status = StudyCaseStatus::Proposal;
// $studyCase->status = StudyCaseStatus::Development;
}

$studyCase->save();
}

$this->info('end');
}
}
64 changes: 64 additions & 0 deletions app/Enums/StudyCaseStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

namespace App\Enums;

use Filament\Support\Contracts\HasLabel;
use Filament\Support\Contracts\HasDescription;
use Filament\Support\Contracts\HasColor;

enum StudyCaseStatus: string implements HasLabel, HasDescription, HasColor
{
// define string values
case Proposal = 'proposal';
case Closed = 'closed';
case Development = 'development';
case ReadyForReview = 'ready_for_review';
case Reviewed = 'reviewed';

// define labels
public function getLabel(): ?string
{
return match ($this) {
self::Proposal => 'Proposal',
self::Closed => 'Closed',
self::Development => 'Development',
self::ReadyForReview => 'Ready for review',
self::Reviewed => 'Reviewed',
};
}

// define descritpions
public function getDescription(): ?string
{
// Proposal : user created a new study case (assumes user will inform reviewer offline when the study case is ready for review)
// Closed : reviewer reviewed and decided NOT to further develop
// Development : reviewer reviewed and decided to further develop
// ReadyForReview : user has filled in all necessary details; user request reviewer to review
// Reviewed : reviewer approved study case; study case is published on the website

return match ($this) {
self::Proposal => 'This has not finished being written yet.',
self::Closed => 'This has been reviewed by reviewer, and decided NOT to further develop',
self::Development => 'This has been reviewed by reviewer, and decided to further develop',
self::ReadyForReview => 'This is ready for a reviewer to review',
self::Reviewed => 'This has been approved by a reviewer. This has been published on the website',
};
}

// define badge colors
public function getColor(): string | array | null
{
// warning (yellow) : pending on reviewer to review
// danger (red) : unsuccessful study case that decided not to further develop
// gray (gray) : no action required from reviewer
// success (green) : reviewer has reviewed and published

return match ($this) {
self::Proposal => 'warning',
self::Closed => 'danger',
self::Development => 'gray',
self::ReadyForReview => 'warning',
self::Reviewed => 'success',
};
}
}
1 change: 1 addition & 0 deletions app/Filament/Admin/Resources/ClaimResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static function getPages(): array
'index' => Pages\ListClaims::route('/'),
'create' => Pages\CreateClaim::route('/create'),
'edit' => Pages\EditClaim::route('/{record}/edit'),
'view' => Pages\ViewClaim::route('/{record}'),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ public function getBreadcrumbs(): array
$casesUrl = route('filament.admin.resources.study-cases.index');
$breadcrumbs[$casesUrl] = 'Cases';

$studyCaseEditUrl = route('filament.admin.resources.study-cases.edit', ['record' => $studyCase->id]);
$studyCaseEditUrl = route('filament.admin.resources.study-cases.manage-case-study-claims', ['record' => $studyCase->id]);
$breadcrumbs[$studyCaseEditUrl] = $studyCase->title;

$claimsUrl = $studyCaseEditUrl . '?tab=-tab-1-tab&activeRelationManager=0';
$claimsUrl = $studyCaseEditUrl;
$breadcrumbs[$claimsUrl] = 'Claims';

$breadcrumbs[] = 'Edit';
Expand All @@ -51,7 +51,7 @@ protected function getRedirectUrl(): string

$ownerRecordId = $params['ownerRecord'];

$redirectUrl = $appUrl . '/admin/study-cases/' . $ownerRecordId . '/edit?tab=-tab-1-tab&activeRelationManager=0';
$redirectUrl = $appUrl . '/admin/study-cases/' . $ownerRecordId . '/manage-case-study-claims';

return $redirectUrl;
}
Expand Down
11 changes: 11 additions & 0 deletions app/Filament/Admin/Resources/ClaimResource/Pages/ViewClaim.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Filament\Admin\Resources\ClaimResource\Pages;

use App\Filament\Admin\Resources\ClaimResource;
use Filament\Resources\Pages\ViewRecord;

class ViewClaim extends ViewRecord
{
protected static string $resource = ClaimResource::class;
}
118 changes: 91 additions & 27 deletions app/Filament/Admin/Resources/StudyCaseResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,61 @@
use Filament\Forms\Form;
use App\Models\StudyCase;
use Filament\Tables\Table;
use App\Enums\StudyCaseStatus;
use Filament\Resources\Resource;
use Filament\Resources\Pages\Page;
use Filament\Forms\Components\Tabs;
use Filament\Tables\Filters\Filter;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Pages\ViewRecord;
use Filament\Pages\SubNavigationPosition;
use Filament\Tables\Filters\SelectFilter;
use Illuminate\Database\Eloquent\Builder;
use Filament\Tables\Filters\TernaryFilter;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use App\Filament\App\Resources\StudyCaseResource\Pages;
use App\Filament\Admin\Resources\StudyCaseResource\RelationManagers;
use App\Filament\App\Resources\StudyCaseResource as AppPanelStudyCaseResource;
use App\Filament\Admin\Resources\StudyCaseResource\Pages\ListStudyCases as AdminPanelListStudyCases;
use App\Filament\App\Resources\StudyCaseResource\RelationManagers\ClaimsRelationManager as AppPanelClaimsRelationManager;
use App\Filament\Admin\Resources\StudyCaseResource\Pages;
use App\Filament\Admin\Resources\StudyCaseResource\RelationManagers;

class StudyCaseResource extends Resource
{
protected static ?string $model = StudyCase::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?int $navigationSort = 1;

protected static SubNavigationPosition $subNavigationPosition = SubNavigationPosition::Top;

public static function getRecordSubNavigation(Page $page): array
{
// hardcode to check page's route name to determine if it is the "view page" for Claims nad Evidence
if ($page instanceof ViewRecord ||
$page->getRoutename() == 'filament.app.resources.study-cases.view-case-study-claims' ||
$page->getRoutename() == 'filament.admin.resources.study-cases.view-case-study-claims') {

$navigation = [
Pages\ViewBasicInformation::class,
Pages\ViewCaseDetails::class,
Pages\ViewCaseStudyClaims::class,
Pages\ViewCommunicationProducts::class,
Pages\ViewPhotos::class,
Pages\ViewConfirmation::class,
];
} else {
$navigation = [
Pages\EditBasicInformation::class,
Pages\EditCaseDetails::class,
Pages\ManageCaseStudyClaims::class,
Pages\EditCommunicationProducts::class,
Pages\EditPhotos::class,
Pages\EditConfirmation::class,
];
}

return $page->generateNavigationItems($navigation);
}

// define translatable string in function
public static function getModelLabel(): string
{
Expand Down Expand Up @@ -63,27 +100,47 @@ public static function table(Table $table): Table
->sortable()
->searchable()
->wrapHeader(),
Tables\Columns\IconColumn::make('ready_for_review')
->label(t('Ready for review'))
->boolean()
->sortable()
->wrapHeader(),
Tables\Columns\IconColumn::make('reviewed')
->label(t('Reviewed'))
->boolean()
Tables\Columns\TextColumn::make('status')
->label(t('Status'))
->badge()
->sortable(),

])
->filters([
TernaryFilter::make('ready_for_review')->label(t('Ready for review')),
TernaryFilter::make('reviewed')->label(t('Reviewed')),
// apply this filter by default to exclude study case with status "closed"
//
// To show study cases with "closed" status, user needs to:
// 1. untick the checkbox of this filter
// 2. select "Closed" in "status" filter
Filter::make('hide_closed_cases')
->label('Hide closed cases')
->default()
->query(fn (Builder $query): Builder => $query->where('status', '!=', 'closed')),

// this filter works properly to show study cases for a selected status
SelectFilter::make('status')
->options(StudyCaseStatus::class),
])
->actions([
Tables\Actions\EditAction::make(),
// view action only available when case can no longer be edited
Tables\Actions\ViewAction::make()
->url(fn($record) => static::getUrl('view-basic-information', ['record' => $record]))
->hidden(function ($record) {
return $record->status != StudyCaseStatus::Reviewed;
}),

// study case can be edited only if reviewer has not reviewed it yet
Tables\Actions\EditAction::make()
->url(fn($record) => static::getUrl('edit-basic-information', ['record' => $record]))
->hidden(function ($record) {
return $record->status == StudyCaseStatus::Reviewed;
}),

Tables\Actions\Action::make('preview_catalogue')
->label(t('Preview'))
->icon('heroicon-o-book-open')
->url(fn (StudyCase $record): string => '/cases/' . $record->id)
->openUrlInNewTab()
->label(t('Preview'))
->icon('heroicon-o-book-open')
->url(fn(StudyCase $record): string => '/cases/' . $record->id)
->openUrlInNewTab()
])
->defaultSort('order')
->reorderable('order')
Expand All @@ -97,23 +154,30 @@ public static function table(Table $table): Table
// re-use app panel Study case relation manager for claims
public static function getRelations(): array
{
return [
AppPanelClaimsRelationManager::class,
];
return [];
}

public static function getPages(): array
{
return [
'index' => Pages\ListStudyCases::route('/'),
// use admin panel ListStudyCases, so that it will use table() function of this class
'index' => AdminPanelListStudyCases::route('/'),

// disable route for creating a new study case
// reviewer should not be able to create new study case.
// study case should be created by leading organisation member.
'edit-basic-information' => Pages\EditBasicInformation::route('/{record}/edit-basic-information'),
'edit-case-details' => Pages\EditCaseDetails::route('/{record}/edit-case-details'),
'manage-case-study-claims' => Pages\ManageCaseStudyClaims::route('/{record}/manage-case-study-claims'),
'edit-communication-products' => Pages\EditCommunicationProducts::route('/{record}/edit-communication-products'),
'edit-photos' => Pages\EditPhotos::route('/{record}/edit-photos'),
'edit-confirmation' => Pages\EditConfirmation::route('/{record}/edit-confirmation'),

// 'create' => Pages\CreateStudyCase::route('/create'),

'edit' => Pages\EditStudyCase::route('/{record}/edit'),
'view' => Pages\ViewBasicInformation::route('/{record}'),
'view-basic-information' => Pages\ViewBasicInformation::route('/{record}/view-basic-information'),
'view-case-details' => Pages\ViewCaseDetails::route('/{record}/view-case-details'),
'view-case-study-claims' => Pages\ViewCaseStudyClaims::route('/{record}/view-case-study-claims'),
'view-communication-products' => Pages\ViewCommunicationProducts::route('/{record}/view-communication-products'),
'view-photos' => Pages\ViewPhotos::route('/{record}/view-photos'),
'view-confirmation' => Pages\ViewConfirmation::route('/{record}/view-confirmation'),
];
}

}
1 change: 1 addition & 0 deletions app/Filament/App/Pages/Register.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Filament\Http\Responses\Auth\Contracts\RegistrationResponse;
use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException;

// this class contains business logic for creating a new user account via email invitation
class Register extends BaseRegister
{
#[Url]
Expand Down
Loading