Phase 2 of Organizr Migration - Front Hall restructure: - Add FrontHallState provider with three modes (dashboard, iframe, settings) - Create QuickLinksPanel widget with categorized links and overflow menus - Add IframeView with platform-aware implementation (web iframe, mobile fallback) - Extract DashboardContent from FrontHallPage - Add QuickLinkSettingsContent placeholder for Phase 4 link editor - Implement QuickLink entity and data layer with Core API datasource - Add default quick links fallback when API unavailable - Update UI_LAYOUT.md with Front Hall panel configurations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
62 lines
1.7 KiB
Dart
62 lines
1.7 KiB
Dart
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
import 'package:tatlock_ui/features/front_hall/domain/entities/quick_link.dart';
|
|
|
|
part 'quick_link_model.freezed.dart';
|
|
part 'quick_link_model.g.dart';
|
|
|
|
/// Quick link data model for API serialization.
|
|
@freezed
|
|
sealed class QuickLinkModel with _$QuickLinkModel {
|
|
const factory QuickLinkModel({
|
|
required String id,
|
|
required String name,
|
|
required String url,
|
|
@JsonKey(name: 'icon_name') required String iconName,
|
|
String? category,
|
|
@Default('iframe') String type,
|
|
@JsonKey(name: 'sort_order') @Default(0) int sortOrder,
|
|
@JsonKey(name: 'is_active') @Default(true) bool isActive,
|
|
}) = _QuickLinkModel;
|
|
|
|
const QuickLinkModel._();
|
|
|
|
factory QuickLinkModel.fromJson(Map<String, dynamic> json) =>
|
|
_$QuickLinkModelFromJson(json);
|
|
|
|
/// Converts to domain entity.
|
|
QuickLink toEntity() {
|
|
return QuickLink(
|
|
id: id,
|
|
name: name,
|
|
url: url,
|
|
iconName: iconName,
|
|
category: category,
|
|
type: _parseType(type),
|
|
sortOrder: sortOrder,
|
|
isActive: isActive,
|
|
);
|
|
}
|
|
|
|
/// Creates model from domain entity.
|
|
factory QuickLinkModel.fromEntity(QuickLink entity) {
|
|
return QuickLinkModel(
|
|
id: entity.id,
|
|
name: entity.name,
|
|
url: entity.url,
|
|
iconName: entity.iconName,
|
|
category: entity.category,
|
|
type: entity.type == QuickLinkType.iframe ? 'iframe' : 'new_tab',
|
|
sortOrder: entity.sortOrder,
|
|
isActive: entity.isActive,
|
|
);
|
|
}
|
|
|
|
QuickLinkType _parseType(String type) {
|
|
return switch (type.toLowerCase()) {
|
|
'iframe' => QuickLinkType.iframe,
|
|
'new_tab' || 'newtab' => QuickLinkType.newTab,
|
|
_ => QuickLinkType.iframe,
|
|
};
|
|
}
|
|
}
|