refactor: Replace attire option 'icon' field with 'description' across the schema and data models, and update the UI to display the new description.

This commit is contained in:
Achintha Isuru
2026-02-24 15:13:06 -05:00
parent 7744dbf1b3
commit b29351a3aa
6 changed files with 68 additions and 68 deletions

View File

@@ -4,23 +4,23 @@ import 'package:equatable/equatable.dart';
/// ///
/// Attire items are specific clothing or equipment required for jobs. /// Attire items are specific clothing or equipment required for jobs.
class AttireItem extends Equatable { class AttireItem extends Equatable {
/// Creates an [AttireItem]. /// Creates an [AttireItem].
const AttireItem({ const AttireItem({
required this.id, required this.id,
required this.label, required this.label,
this.iconName, this.description,
this.imageUrl, this.imageUrl,
this.isMandatory = false, this.isMandatory = false,
}); });
/// Unique identifier of the attire item. /// Unique identifier of the attire item.
final String id; final String id;
/// Display name of the item. /// Display name of the item.
final String label; final String label;
/// Name of the icon to display (mapped in UI). /// Optional description for the attire item.
final String? iconName; final String? description;
/// URL of the reference image. /// URL of the reference image.
final String? imageUrl; final String? imageUrl;
@@ -29,5 +29,11 @@ class AttireItem extends Equatable {
final bool isMandatory; final bool isMandatory;
@override @override
List<Object?> get props => <Object?>[id, label, iconName, imageUrl, isMandatory]; List<Object?> get props => <Object?>[
id,
label,
description,
imageUrl,
isMandatory,
];
} }

View File

@@ -8,26 +8,30 @@ import '../../domain/repositories/attire_repository.dart';
/// ///
/// Delegates data access to [DataConnectService]. /// Delegates data access to [DataConnectService].
class AttireRepositoryImpl implements AttireRepository { class AttireRepositoryImpl implements AttireRepository {
/// Creates an [AttireRepositoryImpl]. /// Creates an [AttireRepositoryImpl].
AttireRepositoryImpl({DataConnectService? service}) AttireRepositoryImpl({DataConnectService? service})
: _service = service ?? DataConnectService.instance; : _service = service ?? DataConnectService.instance;
/// The Data Connect service. /// The Data Connect service.
final DataConnectService _service; final DataConnectService _service;
@override @override
Future<List<AttireItem>> getAttireOptions() async { Future<List<AttireItem>> getAttireOptions() async {
return _service.run(() async { return _service.run(() async {
final QueryResult<ListAttireOptionsData, void> result = final QueryResult<ListAttireOptionsData, void> result = await _service
await _service.connector.listAttireOptions().execute(); .connector
.listAttireOptions()
.execute();
return result.data.attireOptions return result.data.attireOptions
.map((ListAttireOptionsAttireOptions e) => AttireItem( .map(
id: e.itemId, (ListAttireOptionsAttireOptions e) => AttireItem(
label: e.label, id: e.itemId,
iconName: e.icon, label: e.label,
imageUrl: e.imageUrl, description: e.description,
isMandatory: e.isMandatory ?? false, imageUrl: e.imageUrl,
)) isMandatory: e.isMandatory ?? false,
),
)
.toList(); .toList();
}); });
} }

View File

@@ -5,7 +5,6 @@ import 'package:core_localization/core_localization.dart';
import 'package:krow_domain/krow_domain.dart'; import 'package:krow_domain/krow_domain.dart';
class AttireGrid extends StatelessWidget { class AttireGrid extends StatelessWidget {
const AttireGrid({ const AttireGrid({
super.key, super.key,
required this.items, required this.items,
@@ -53,7 +52,9 @@ class AttireGrid extends StatelessWidget {
) { ) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isSelected ? UiColors.primary.withOpacity(0.1) : Colors.transparent, color: isSelected
? UiColors.primary.withOpacity(0.1)
: Colors.transparent,
borderRadius: UiConstants.radiusSm, borderRadius: UiConstants.radiusSm,
border: Border.all( border: Border.all(
color: isSelected ? UiColors.primary : UiColors.border, color: isSelected ? UiColors.primary : UiColors.border,
@@ -67,19 +68,17 @@ class AttireGrid extends StatelessWidget {
top: UiConstants.space2, top: UiConstants.space2,
left: UiConstants.space2, left: UiConstants.space2,
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
horizontal: 6,
vertical: 2,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: UiColors.destructive, // Red color: UiColors.destructive, // Red
borderRadius: UiConstants.radiusSm, borderRadius: UiConstants.radiusSm,
), ),
child: Text( child: Text(
t.staff_profile_attire.status.required, t.staff_profile_attire.status.required,
style: UiTypography.body3m.copyWith( // 12px Medium -> Bold style: UiTypography.body3m.copyWith(
// 12px Medium -> Bold
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 9, fontSize: 9,
color: UiColors.white, color: UiColors.white,
), ),
), ),
@@ -97,11 +96,7 @@ class AttireGrid extends StatelessWidget {
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: const Center( child: const Center(
child: Icon( child: Icon(UiIcons.check, color: UiColors.white, size: 12),
UiIcons.check,
color: UiColors.white,
size: 12,
),
), ),
), ),
), ),
@@ -119,26 +114,34 @@ class AttireGrid extends StatelessWidget {
height: 80, height: 80,
width: 80, width: 80,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(UiConstants.radiusBase), borderRadius: BorderRadius.circular(
UiConstants.radiusBase,
),
image: DecorationImage( image: DecorationImage(
image: NetworkImage(item.imageUrl!), image: NetworkImage(item.imageUrl!),
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
) )
: Icon( : const Icon(
_getIcon(item.iconName), UiIcons.shirt,
size: 48, size: 48,
color: UiColors.textPrimary, // Was charcoal color: UiColors.iconSecondary,
), ),
const SizedBox(height: UiConstants.space2), const SizedBox(height: UiConstants.space2),
Text( Text(
item.label, item.label,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: UiTypography.body2m.copyWith( style: UiTypography.body2m.textPrimary,
color: UiColors.textPrimary,
),
), ),
if (item.description != null)
Text(
item.description!,
textAlign: TextAlign.center,
style: UiTypography.body3r.textSecondary,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
], ],
), ),
), ),
@@ -158,7 +161,9 @@ class AttireGrid extends StatelessWidget {
border: Border.all( border: Border.all(
color: hasPhoto ? UiColors.primary : UiColors.border, color: hasPhoto ? UiColors.primary : UiColors.border,
), ),
borderRadius: BorderRadius.circular(UiConstants.radiusBase), borderRadius: BorderRadius.circular(
UiConstants.radiusBase,
),
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@@ -169,7 +174,9 @@ class AttireGrid extends StatelessWidget {
height: 12, height: 12,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2, strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(UiColors.primary), valueColor: AlwaysStoppedAnimation<Color>(
UiColors.primary,
),
), ),
) )
else if (hasPhoto) else if (hasPhoto)
@@ -189,10 +196,12 @@ class AttireGrid extends StatelessWidget {
isUploading isUploading
? '...' ? '...'
: hasPhoto : hasPhoto
? t.staff_profile_attire.status.added ? t.staff_profile_attire.status.added
: t.staff_profile_attire.status.add_photo, : t.staff_profile_attire.status.add_photo,
style: UiTypography.body3m.copyWith( style: UiTypography.body3m.copyWith(
color: hasPhoto ? UiColors.primary : UiColors.textSecondary, color: hasPhoto
? UiColors.primary
: UiColors.textSecondary,
), ),
), ),
], ],
@@ -217,23 +226,4 @@ class AttireGrid extends StatelessWidget {
), ),
); );
} }
IconData _getIcon(String? name) {
switch (name) {
case 'footprints':
return UiIcons.footprints;
case 'scissors':
return UiIcons.scissors;
case 'user':
return UiIcons.user;
case 'shirt':
return UiIcons.shirt;
case 'hardHat':
return UiIcons.hardHat;
case 'chefHat':
return UiIcons.chefHat;
default:
return UiIcons.help;
}
}
} }

View File

@@ -1,7 +1,7 @@
mutation createAttireOption( mutation createAttireOption(
$itemId: String! $itemId: String!
$label: String! $label: String!
$icon: String $description: String
$imageUrl: String $imageUrl: String
$isMandatory: Boolean $isMandatory: Boolean
$vendorId: UUID $vendorId: UUID
@@ -10,7 +10,7 @@ mutation createAttireOption(
data: { data: {
itemId: $itemId itemId: $itemId
label: $label label: $label
icon: $icon description: $description
imageUrl: $imageUrl imageUrl: $imageUrl
isMandatory: $isMandatory isMandatory: $isMandatory
vendorId: $vendorId vendorId: $vendorId
@@ -22,7 +22,7 @@ mutation updateAttireOption(
$id: UUID! $id: UUID!
$itemId: String $itemId: String
$label: String $label: String
$icon: String $description: String
$imageUrl: String $imageUrl: String
$isMandatory: Boolean $isMandatory: Boolean
$vendorId: UUID $vendorId: UUID
@@ -32,7 +32,7 @@ mutation updateAttireOption(
data: { data: {
itemId: $itemId itemId: $itemId
label: $label label: $label
icon: $icon description: $description
imageUrl: $imageUrl imageUrl: $imageUrl
isMandatory: $isMandatory isMandatory: $isMandatory
vendorId: $vendorId vendorId: $vendorId

View File

@@ -3,7 +3,7 @@ query listAttireOptions @auth(level: USER) {
id id
itemId itemId
label label
icon description
imageUrl imageUrl
isMandatory isMandatory
vendorId vendorId
@@ -16,7 +16,7 @@ query getAttireOptionById($id: UUID!) @auth(level: USER) {
id id
itemId itemId
label label
icon description
imageUrl imageUrl
isMandatory isMandatory
vendorId vendorId
@@ -39,7 +39,7 @@ query filterAttireOptions(
id id
itemId itemId
label label
icon description
imageUrl imageUrl
isMandatory isMandatory
vendorId vendorId

View File

@@ -2,7 +2,7 @@ type AttireOption @table(name: "attire_options") {
id: UUID! @default(expr: "uuidV4()") id: UUID! @default(expr: "uuidV4()")
itemId: String! itemId: String!
label: String! label: String!
icon: String description: String
imageUrl: String imageUrl: String
isMandatory: Boolean isMandatory: Boolean