feat: 대시보드에 라이선스 만료 요약 및 Lookup 데이터 캐싱 시스템 구현
- License Expiry Summary API 연동 완료 - 30/60/90일 내 만료 예정 라이선스 요약 표시 - 대시보드 상단에 알림 카드로 통합 - 만료 임박 순서로 색상 구분 (빨강/주황/노랑) - Lookup 데이터 전역 캐싱 시스템 구축 - LookupService 및 RemoteDataSource 생성 - 전체 lookup 데이터 일괄 로드 및 캐싱 - 타입별 필터링 지원 - 새로운 모델 추가 - LicenseExpirySummary (Freezed) - LookupData, LookupCategory, LookupItem 모델 - CLAUDE.md 문서 업데이트 - 미사용 API 활용 계획 추가 - 구현 우선순위 정의 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
60
CLAUDE.md
60
CLAUDE.md
@@ -118,6 +118,58 @@ Infrastructure:
|
||||
priority: LOW
|
||||
```
|
||||
|
||||
## 🔌 Unused Backend API Integration Plan
|
||||
|
||||
### 현재 백엔드에 구현되었으나 프론트엔드에서 미사용 중인 API
|
||||
|
||||
#### 1. `/overview/license-expiry` - 라이선스 만료 요약
|
||||
**용도**: 30일/60일/90일 내 만료 예정인 라이선스 요약 정보 제공
|
||||
**활용 계획**:
|
||||
- **위치**: Dashboard 화면 상단 알림 배너
|
||||
- **구현 방법**:
|
||||
- 만료 임박 라이선스 카운트를 배지로 표시
|
||||
- 클릭 시 상세 라이선스 목록으로 이동
|
||||
- 관리자/매니저 권한일 때만 표시
|
||||
- **예상 효과**: 라이선스 갱신 누락 방지, 사전 대응 가능
|
||||
|
||||
#### 2. `/lookups` - 전체 조회 데이터
|
||||
**용도**: 시스템 전체 드롭다운/셀렉트 박스용 마스터 데이터 제공
|
||||
**활용 계획**:
|
||||
- **위치**: 앱 초기화 시 한 번 호출하여 캐싱
|
||||
- **구현 방법**:
|
||||
- `LookupService` 생성하여 전역 상태 관리
|
||||
- 장비 타입, 상태 코드, 제조사 목록 등 일괄 관리
|
||||
- 각 화면에서 개별 API 호출 대신 캐시된 데이터 사용
|
||||
- **예상 효과**: API 호출 횟수 감소, 응답 속도 향상
|
||||
|
||||
#### 3. `/lookups/type` - 타입별 조회 데이터
|
||||
**용도**: 특정 타입의 조회 데이터만 선택적으로 가져오기
|
||||
**활용 계획**:
|
||||
- **위치**: 대량 데이터 입력 화면 (장비 일괄 등록, Excel 임포트)
|
||||
- **구현 방법**:
|
||||
- 필요한 타입만 선택적으로 로드
|
||||
- 동적 폼 생성 시 활용
|
||||
- 타입별 유효성 검증 규칙 적용
|
||||
- **예상 효과**: 메모리 사용량 최적화, 동적 UI 구성 가능
|
||||
|
||||
#### 4. `/health` - 시스템 상태 체크
|
||||
**용도**: API 서버 상태 및 DB 연결 상태 확인
|
||||
**활용 계획**:
|
||||
- **위치**:
|
||||
- 로그인 화면 하단 (서버 상태 인디케이터)
|
||||
- 관리자 대시보드 (시스템 모니터링 위젯)
|
||||
- **구현 방법**:
|
||||
- 30초 간격 폴링으로 서버 상태 모니터링
|
||||
- 연결 실패 시 자동 재시도 및 사용자 알림
|
||||
- 서버 점검 시간 사전 공지 표시
|
||||
- **예상 효과**: 시스템 안정성 향상, 장애 조기 감지
|
||||
|
||||
### 구현 우선순위
|
||||
1. **Phase 1 (1주차)**: `/overview/license-expiry` - 대시보드 통합
|
||||
2. **Phase 2 (2주차)**: `/lookups` - 전역 캐싱 시스템 구축
|
||||
3. **Phase 3 (3주차)**: `/health` - 시스템 모니터링 구현
|
||||
4. **Phase 4 (4주차)**: `/lookups/type` - 동적 폼 시스템 구축
|
||||
|
||||
## 📋 TODO List
|
||||
|
||||
### Immediate (This Week)
|
||||
@@ -125,18 +177,22 @@ Infrastructure:
|
||||
- [ ] 대시보드 차트 구현 (Chart.js 통합)
|
||||
- [ ] 시리얼 번호 중복 체크 백엔드 구현
|
||||
- [ ] 권한 체크 누락 화면 수정
|
||||
- [ ] `/overview/license-expiry` API 연동 (대시보드 알림 배너)
|
||||
|
||||
### Short Term (This Month)
|
||||
- [ ] 장비 대여/반납 기능 구현
|
||||
- [ ] 고급 검색 필터 구현
|
||||
- [ ] Excel 내보내기 기능
|
||||
- [ ] 성능 최적화 (가상 스크롤링)
|
||||
- [ ] `/lookups` API 활용한 전역 캐싱 시스템 구축
|
||||
- [ ] `/health` API 활용한 서버 상태 모니터링
|
||||
|
||||
### Long Term
|
||||
- [ ] 모바일 앱 최적화
|
||||
- [ ] 푸시 알림 시스템
|
||||
- [ ] 다국어 지원 (영어)
|
||||
- [ ] 대시보드 커스터마이징
|
||||
- [ ] `/lookups/type` API 활용한 동적 폼 시스템
|
||||
|
||||
## 🔑 Key Decisions
|
||||
|
||||
@@ -194,5 +250,5 @@ API Source Code: /Users/maximilian.j.sul/Documents/flutter/superport_api
|
||||
|
||||
**Project Stage**: Development (70% Complete)
|
||||
**Next Milestone**: Beta Release (2025-02-01)
|
||||
**Last Updated**: 2025-01-08
|
||||
**Version**: 3.0
|
||||
**Last Updated**: 2025-01-09
|
||||
**Version**: 3.1
|
||||
@@ -6,6 +6,7 @@ import 'package:superport/core/errors/failures.dart';
|
||||
import 'package:superport/data/datasources/remote/api_client.dart';
|
||||
import 'package:superport/data/models/dashboard/equipment_status_distribution.dart';
|
||||
import 'package:superport/data/models/dashboard/expiring_license.dart';
|
||||
import 'package:superport/data/models/dashboard/license_expiry_summary.dart';
|
||||
import 'package:superport/data/models/dashboard/overview_stats.dart';
|
||||
import 'package:superport/data/models/dashboard/recent_activity.dart';
|
||||
|
||||
@@ -14,6 +15,7 @@ abstract class DashboardRemoteDataSource {
|
||||
Future<Either<Failure, List<RecentActivity>>> getRecentActivities();
|
||||
Future<Either<Failure, EquipmentStatusDistribution>> getEquipmentStatusDistribution();
|
||||
Future<Either<Failure, List<ExpiringLicense>>> getExpiringLicenses({int days = 30});
|
||||
Future<Either<Failure, LicenseExpirySummary>> getLicenseExpirySummary();
|
||||
}
|
||||
|
||||
@LazySingleton(as: DashboardRemoteDataSource)
|
||||
@@ -105,6 +107,25 @@ class DashboardRemoteDataSourceImpl implements DashboardRemoteDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, LicenseExpirySummary>> getLicenseExpirySummary() async {
|
||||
try {
|
||||
final response = await _apiClient.get('/overview/license-expiry');
|
||||
|
||||
if (response.data != null && response.data['success'] == true && response.data['data'] != null) {
|
||||
final summary = LicenseExpirySummary.fromJson(response.data['data']);
|
||||
return Right(summary);
|
||||
} else {
|
||||
final errorMessage = response.data?['error']?['message'] ?? '응답 데이터가 올바르지 않습니다';
|
||||
return Left(ServerFailure(message: errorMessage));
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
return Left(_handleDioError(e));
|
||||
} catch (e) {
|
||||
return Left(ServerFailure(message: '라이선스 만료 요약을 가져오는 중 오류가 발생했습니다: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
Failure _handleDioError(DioException error) {
|
||||
switch (error.type) {
|
||||
case DioExceptionType.connectionTimeout:
|
||||
|
||||
102
lib/data/datasources/remote/lookup_remote_datasource.dart
Normal file
102
lib/data/datasources/remote/lookup_remote_datasource.dart
Normal file
@@ -0,0 +1,102 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:superport/core/errors/failures.dart';
|
||||
import 'package:superport/data/datasources/remote/api_client.dart';
|
||||
import 'package:superport/data/models/lookups/lookup_data.dart';
|
||||
|
||||
abstract class LookupRemoteDataSource {
|
||||
Future<Either<Failure, LookupData>> getAllLookups();
|
||||
Future<Either<Failure, Map<String, List<LookupItem>>>> getLookupsByType(String type);
|
||||
}
|
||||
|
||||
@LazySingleton(as: LookupRemoteDataSource)
|
||||
class LookupRemoteDataSourceImpl implements LookupRemoteDataSource {
|
||||
final ApiClient _apiClient;
|
||||
|
||||
LookupRemoteDataSourceImpl(this._apiClient);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, LookupData>> getAllLookups() async {
|
||||
try {
|
||||
final response = await _apiClient.get('/lookups');
|
||||
|
||||
if (response.data != null && response.data['success'] == true && response.data['data'] != null) {
|
||||
final lookupData = LookupData.fromJson(response.data['data']);
|
||||
return Right(lookupData);
|
||||
} else {
|
||||
final errorMessage = response.data?['error']?['message'] ?? '응답 데이터가 올바르지 않습니다';
|
||||
return Left(ServerFailure(message: errorMessage));
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
return Left(_handleDioError(e));
|
||||
} catch (e) {
|
||||
return Left(ServerFailure(message: '조회 데이터를 가져오는 중 오류가 발생했습니다: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, Map<String, List<LookupItem>>>> getLookupsByType(String type) async {
|
||||
try {
|
||||
final response = await _apiClient.get(
|
||||
'/lookups/type',
|
||||
queryParameters: {'lookup_type': type},
|
||||
);
|
||||
|
||||
if (response.data != null && response.data['success'] == true && response.data['data'] != null) {
|
||||
final data = response.data['data'] as Map<String, dynamic>;
|
||||
final result = <String, List<LookupItem>>{};
|
||||
|
||||
data.forEach((key, value) {
|
||||
if (value is List) {
|
||||
result[key] = value.map((item) => LookupItem.fromJson(item)).toList();
|
||||
}
|
||||
});
|
||||
|
||||
return Right(result);
|
||||
} else {
|
||||
final errorMessage = response.data?['error']?['message'] ?? '응답 데이터가 올바르지 않습니다';
|
||||
return Left(ServerFailure(message: errorMessage));
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
return Left(_handleDioError(e));
|
||||
} catch (e) {
|
||||
return Left(ServerFailure(message: '타입별 조회 데이터를 가져오는 중 오류가 발생했습니다: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
Failure _handleDioError(DioException error) {
|
||||
switch (error.type) {
|
||||
case DioExceptionType.connectionTimeout:
|
||||
case DioExceptionType.sendTimeout:
|
||||
case DioExceptionType.receiveTimeout:
|
||||
return NetworkFailure(message: '네트워크 연결 시간이 초과되었습니다');
|
||||
case DioExceptionType.connectionError:
|
||||
return NetworkFailure(message: '서버에 연결할 수 없습니다');
|
||||
case DioExceptionType.badResponse:
|
||||
final statusCode = error.response?.statusCode ?? 0;
|
||||
final errorData = error.response?.data;
|
||||
|
||||
String message;
|
||||
if (errorData is Map) {
|
||||
message = errorData['error']?['message'] ??
|
||||
errorData['message'] ??
|
||||
'서버 오류가 발생했습니다';
|
||||
} else {
|
||||
message = '서버 오류가 발생했습니다';
|
||||
}
|
||||
|
||||
if (statusCode == 401) {
|
||||
return AuthenticationFailure(message: '인증이 만료되었습니다');
|
||||
} else if (statusCode == 403) {
|
||||
return AuthenticationFailure(message: '접근 권한이 없습니다');
|
||||
} else {
|
||||
return ServerFailure(message: message);
|
||||
}
|
||||
case DioExceptionType.cancel:
|
||||
return ServerFailure(message: '요청이 취소되었습니다');
|
||||
default:
|
||||
return ServerFailure(message: '알 수 없는 오류가 발생했습니다');
|
||||
}
|
||||
}
|
||||
}
|
||||
38
lib/data/models/dashboard/license_expiry_summary.dart
Normal file
38
lib/data/models/dashboard/license_expiry_summary.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'license_expiry_summary.freezed.dart';
|
||||
part 'license_expiry_summary.g.dart';
|
||||
|
||||
@freezed
|
||||
class LicenseExpirySummary with _$LicenseExpirySummary {
|
||||
const factory LicenseExpirySummary({
|
||||
@JsonKey(name: 'within_30_days') required int within30Days,
|
||||
@JsonKey(name: 'within_60_days') required int within60Days,
|
||||
@JsonKey(name: 'within_90_days') required int within90Days,
|
||||
@JsonKey(name: 'expired') required int expired,
|
||||
@JsonKey(name: 'total_active') required int totalActive,
|
||||
@JsonKey(name: 'licenses') required List<LicenseExpiryDetail> licenses,
|
||||
}) = _LicenseExpirySummary;
|
||||
|
||||
factory LicenseExpirySummary.fromJson(Map<String, dynamic> json) =>
|
||||
_$LicenseExpirySummaryFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class LicenseExpiryDetail with _$LicenseExpiryDetail {
|
||||
const factory LicenseExpiryDetail({
|
||||
required int id,
|
||||
@JsonKey(name: 'equipment_id') required int equipmentId,
|
||||
@JsonKey(name: 'equipment_name') required String equipmentName,
|
||||
@JsonKey(name: 'serial_number') required String serialNumber,
|
||||
@JsonKey(name: 'company_name') required String companyName,
|
||||
@JsonKey(name: 'license_type') required String licenseType,
|
||||
@JsonKey(name: 'start_date') required String startDate,
|
||||
@JsonKey(name: 'end_date') required String endDate,
|
||||
@JsonKey(name: 'days_remaining') required int daysRemaining,
|
||||
@JsonKey(name: 'is_expired') required bool isExpired,
|
||||
}) = _LicenseExpiryDetail;
|
||||
|
||||
factory LicenseExpiryDetail.fromJson(Map<String, dynamic> json) =>
|
||||
_$LicenseExpiryDetailFromJson(json);
|
||||
}
|
||||
690
lib/data/models/dashboard/license_expiry_summary.freezed.dart
Normal file
690
lib/data/models/dashboard/license_expiry_summary.freezed.dart
Normal file
@@ -0,0 +1,690 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'license_expiry_summary.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
LicenseExpirySummary _$LicenseExpirySummaryFromJson(Map<String, dynamic> json) {
|
||||
return _LicenseExpirySummary.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LicenseExpirySummary {
|
||||
@JsonKey(name: 'within_30_days')
|
||||
int get within30Days => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'within_60_days')
|
||||
int get within60Days => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'within_90_days')
|
||||
int get within90Days => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'expired')
|
||||
int get expired => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'total_active')
|
||||
int get totalActive => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'licenses')
|
||||
List<LicenseExpiryDetail> get licenses => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this LicenseExpirySummary to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LicenseExpirySummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$LicenseExpirySummaryCopyWith<LicenseExpirySummary> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LicenseExpirySummaryCopyWith<$Res> {
|
||||
factory $LicenseExpirySummaryCopyWith(LicenseExpirySummary value,
|
||||
$Res Function(LicenseExpirySummary) then) =
|
||||
_$LicenseExpirySummaryCopyWithImpl<$Res, LicenseExpirySummary>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'within_30_days') int within30Days,
|
||||
@JsonKey(name: 'within_60_days') int within60Days,
|
||||
@JsonKey(name: 'within_90_days') int within90Days,
|
||||
@JsonKey(name: 'expired') int expired,
|
||||
@JsonKey(name: 'total_active') int totalActive,
|
||||
@JsonKey(name: 'licenses') List<LicenseExpiryDetail> licenses});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LicenseExpirySummaryCopyWithImpl<$Res,
|
||||
$Val extends LicenseExpirySummary>
|
||||
implements $LicenseExpirySummaryCopyWith<$Res> {
|
||||
_$LicenseExpirySummaryCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LicenseExpirySummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? within30Days = null,
|
||||
Object? within60Days = null,
|
||||
Object? within90Days = null,
|
||||
Object? expired = null,
|
||||
Object? totalActive = null,
|
||||
Object? licenses = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
within30Days: null == within30Days
|
||||
? _value.within30Days
|
||||
: within30Days // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
within60Days: null == within60Days
|
||||
? _value.within60Days
|
||||
: within60Days // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
within90Days: null == within90Days
|
||||
? _value.within90Days
|
||||
: within90Days // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
expired: null == expired
|
||||
? _value.expired
|
||||
: expired // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
totalActive: null == totalActive
|
||||
? _value.totalActive
|
||||
: totalActive // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
licenses: null == licenses
|
||||
? _value.licenses
|
||||
: licenses // ignore: cast_nullable_to_non_nullable
|
||||
as List<LicenseExpiryDetail>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LicenseExpirySummaryImplCopyWith<$Res>
|
||||
implements $LicenseExpirySummaryCopyWith<$Res> {
|
||||
factory _$$LicenseExpirySummaryImplCopyWith(_$LicenseExpirySummaryImpl value,
|
||||
$Res Function(_$LicenseExpirySummaryImpl) then) =
|
||||
__$$LicenseExpirySummaryImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'within_30_days') int within30Days,
|
||||
@JsonKey(name: 'within_60_days') int within60Days,
|
||||
@JsonKey(name: 'within_90_days') int within90Days,
|
||||
@JsonKey(name: 'expired') int expired,
|
||||
@JsonKey(name: 'total_active') int totalActive,
|
||||
@JsonKey(name: 'licenses') List<LicenseExpiryDetail> licenses});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LicenseExpirySummaryImplCopyWithImpl<$Res>
|
||||
extends _$LicenseExpirySummaryCopyWithImpl<$Res, _$LicenseExpirySummaryImpl>
|
||||
implements _$$LicenseExpirySummaryImplCopyWith<$Res> {
|
||||
__$$LicenseExpirySummaryImplCopyWithImpl(_$LicenseExpirySummaryImpl _value,
|
||||
$Res Function(_$LicenseExpirySummaryImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of LicenseExpirySummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? within30Days = null,
|
||||
Object? within60Days = null,
|
||||
Object? within90Days = null,
|
||||
Object? expired = null,
|
||||
Object? totalActive = null,
|
||||
Object? licenses = null,
|
||||
}) {
|
||||
return _then(_$LicenseExpirySummaryImpl(
|
||||
within30Days: null == within30Days
|
||||
? _value.within30Days
|
||||
: within30Days // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
within60Days: null == within60Days
|
||||
? _value.within60Days
|
||||
: within60Days // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
within90Days: null == within90Days
|
||||
? _value.within90Days
|
||||
: within90Days // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
expired: null == expired
|
||||
? _value.expired
|
||||
: expired // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
totalActive: null == totalActive
|
||||
? _value.totalActive
|
||||
: totalActive // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
licenses: null == licenses
|
||||
? _value._licenses
|
||||
: licenses // ignore: cast_nullable_to_non_nullable
|
||||
as List<LicenseExpiryDetail>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$LicenseExpirySummaryImpl implements _LicenseExpirySummary {
|
||||
const _$LicenseExpirySummaryImpl(
|
||||
{@JsonKey(name: 'within_30_days') required this.within30Days,
|
||||
@JsonKey(name: 'within_60_days') required this.within60Days,
|
||||
@JsonKey(name: 'within_90_days') required this.within90Days,
|
||||
@JsonKey(name: 'expired') required this.expired,
|
||||
@JsonKey(name: 'total_active') required this.totalActive,
|
||||
@JsonKey(name: 'licenses')
|
||||
required final List<LicenseExpiryDetail> licenses})
|
||||
: _licenses = licenses;
|
||||
|
||||
factory _$LicenseExpirySummaryImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$LicenseExpirySummaryImplFromJson(json);
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'within_30_days')
|
||||
final int within30Days;
|
||||
@override
|
||||
@JsonKey(name: 'within_60_days')
|
||||
final int within60Days;
|
||||
@override
|
||||
@JsonKey(name: 'within_90_days')
|
||||
final int within90Days;
|
||||
@override
|
||||
@JsonKey(name: 'expired')
|
||||
final int expired;
|
||||
@override
|
||||
@JsonKey(name: 'total_active')
|
||||
final int totalActive;
|
||||
final List<LicenseExpiryDetail> _licenses;
|
||||
@override
|
||||
@JsonKey(name: 'licenses')
|
||||
List<LicenseExpiryDetail> get licenses {
|
||||
if (_licenses is EqualUnmodifiableListView) return _licenses;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_licenses);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LicenseExpirySummary(within30Days: $within30Days, within60Days: $within60Days, within90Days: $within90Days, expired: $expired, totalActive: $totalActive, licenses: $licenses)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LicenseExpirySummaryImpl &&
|
||||
(identical(other.within30Days, within30Days) ||
|
||||
other.within30Days == within30Days) &&
|
||||
(identical(other.within60Days, within60Days) ||
|
||||
other.within60Days == within60Days) &&
|
||||
(identical(other.within90Days, within90Days) ||
|
||||
other.within90Days == within90Days) &&
|
||||
(identical(other.expired, expired) || other.expired == expired) &&
|
||||
(identical(other.totalActive, totalActive) ||
|
||||
other.totalActive == totalActive) &&
|
||||
const DeepCollectionEquality().equals(other._licenses, _licenses));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
within30Days,
|
||||
within60Days,
|
||||
within90Days,
|
||||
expired,
|
||||
totalActive,
|
||||
const DeepCollectionEquality().hash(_licenses));
|
||||
|
||||
/// Create a copy of LicenseExpirySummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LicenseExpirySummaryImplCopyWith<_$LicenseExpirySummaryImpl>
|
||||
get copyWith =>
|
||||
__$$LicenseExpirySummaryImplCopyWithImpl<_$LicenseExpirySummaryImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$LicenseExpirySummaryImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _LicenseExpirySummary implements LicenseExpirySummary {
|
||||
const factory _LicenseExpirySummary(
|
||||
{@JsonKey(name: 'within_30_days') required final int within30Days,
|
||||
@JsonKey(name: 'within_60_days') required final int within60Days,
|
||||
@JsonKey(name: 'within_90_days') required final int within90Days,
|
||||
@JsonKey(name: 'expired') required final int expired,
|
||||
@JsonKey(name: 'total_active') required final int totalActive,
|
||||
@JsonKey(name: 'licenses')
|
||||
required final List<LicenseExpiryDetail> licenses}) =
|
||||
_$LicenseExpirySummaryImpl;
|
||||
|
||||
factory _LicenseExpirySummary.fromJson(Map<String, dynamic> json) =
|
||||
_$LicenseExpirySummaryImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'within_30_days')
|
||||
int get within30Days;
|
||||
@override
|
||||
@JsonKey(name: 'within_60_days')
|
||||
int get within60Days;
|
||||
@override
|
||||
@JsonKey(name: 'within_90_days')
|
||||
int get within90Days;
|
||||
@override
|
||||
@JsonKey(name: 'expired')
|
||||
int get expired;
|
||||
@override
|
||||
@JsonKey(name: 'total_active')
|
||||
int get totalActive;
|
||||
@override
|
||||
@JsonKey(name: 'licenses')
|
||||
List<LicenseExpiryDetail> get licenses;
|
||||
|
||||
/// Create a copy of LicenseExpirySummary
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LicenseExpirySummaryImplCopyWith<_$LicenseExpirySummaryImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
LicenseExpiryDetail _$LicenseExpiryDetailFromJson(Map<String, dynamic> json) {
|
||||
return _LicenseExpiryDetail.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LicenseExpiryDetail {
|
||||
int get id => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'equipment_id')
|
||||
int get equipmentId => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'equipment_name')
|
||||
String get equipmentName => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'serial_number')
|
||||
String get serialNumber => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'company_name')
|
||||
String get companyName => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'license_type')
|
||||
String get licenseType => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'start_date')
|
||||
String get startDate => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'end_date')
|
||||
String get endDate => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'days_remaining')
|
||||
int get daysRemaining => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'is_expired')
|
||||
bool get isExpired => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this LicenseExpiryDetail to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LicenseExpiryDetail
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$LicenseExpiryDetailCopyWith<LicenseExpiryDetail> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LicenseExpiryDetailCopyWith<$Res> {
|
||||
factory $LicenseExpiryDetailCopyWith(
|
||||
LicenseExpiryDetail value, $Res Function(LicenseExpiryDetail) then) =
|
||||
_$LicenseExpiryDetailCopyWithImpl<$Res, LicenseExpiryDetail>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
@JsonKey(name: 'equipment_id') int equipmentId,
|
||||
@JsonKey(name: 'equipment_name') String equipmentName,
|
||||
@JsonKey(name: 'serial_number') String serialNumber,
|
||||
@JsonKey(name: 'company_name') String companyName,
|
||||
@JsonKey(name: 'license_type') String licenseType,
|
||||
@JsonKey(name: 'start_date') String startDate,
|
||||
@JsonKey(name: 'end_date') String endDate,
|
||||
@JsonKey(name: 'days_remaining') int daysRemaining,
|
||||
@JsonKey(name: 'is_expired') bool isExpired});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LicenseExpiryDetailCopyWithImpl<$Res, $Val extends LicenseExpiryDetail>
|
||||
implements $LicenseExpiryDetailCopyWith<$Res> {
|
||||
_$LicenseExpiryDetailCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LicenseExpiryDetail
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? equipmentId = null,
|
||||
Object? equipmentName = null,
|
||||
Object? serialNumber = null,
|
||||
Object? companyName = null,
|
||||
Object? licenseType = null,
|
||||
Object? startDate = null,
|
||||
Object? endDate = null,
|
||||
Object? daysRemaining = null,
|
||||
Object? isExpired = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
equipmentId: null == equipmentId
|
||||
? _value.equipmentId
|
||||
: equipmentId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
equipmentName: null == equipmentName
|
||||
? _value.equipmentName
|
||||
: equipmentName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
serialNumber: null == serialNumber
|
||||
? _value.serialNumber
|
||||
: serialNumber // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
companyName: null == companyName
|
||||
? _value.companyName
|
||||
: companyName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
licenseType: null == licenseType
|
||||
? _value.licenseType
|
||||
: licenseType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
startDate: null == startDate
|
||||
? _value.startDate
|
||||
: startDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
endDate: null == endDate
|
||||
? _value.endDate
|
||||
: endDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
daysRemaining: null == daysRemaining
|
||||
? _value.daysRemaining
|
||||
: daysRemaining // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isExpired: null == isExpired
|
||||
? _value.isExpired
|
||||
: isExpired // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LicenseExpiryDetailImplCopyWith<$Res>
|
||||
implements $LicenseExpiryDetailCopyWith<$Res> {
|
||||
factory _$$LicenseExpiryDetailImplCopyWith(_$LicenseExpiryDetailImpl value,
|
||||
$Res Function(_$LicenseExpiryDetailImpl) then) =
|
||||
__$$LicenseExpiryDetailImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
@JsonKey(name: 'equipment_id') int equipmentId,
|
||||
@JsonKey(name: 'equipment_name') String equipmentName,
|
||||
@JsonKey(name: 'serial_number') String serialNumber,
|
||||
@JsonKey(name: 'company_name') String companyName,
|
||||
@JsonKey(name: 'license_type') String licenseType,
|
||||
@JsonKey(name: 'start_date') String startDate,
|
||||
@JsonKey(name: 'end_date') String endDate,
|
||||
@JsonKey(name: 'days_remaining') int daysRemaining,
|
||||
@JsonKey(name: 'is_expired') bool isExpired});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LicenseExpiryDetailImplCopyWithImpl<$Res>
|
||||
extends _$LicenseExpiryDetailCopyWithImpl<$Res, _$LicenseExpiryDetailImpl>
|
||||
implements _$$LicenseExpiryDetailImplCopyWith<$Res> {
|
||||
__$$LicenseExpiryDetailImplCopyWithImpl(_$LicenseExpiryDetailImpl _value,
|
||||
$Res Function(_$LicenseExpiryDetailImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of LicenseExpiryDetail
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? equipmentId = null,
|
||||
Object? equipmentName = null,
|
||||
Object? serialNumber = null,
|
||||
Object? companyName = null,
|
||||
Object? licenseType = null,
|
||||
Object? startDate = null,
|
||||
Object? endDate = null,
|
||||
Object? daysRemaining = null,
|
||||
Object? isExpired = null,
|
||||
}) {
|
||||
return _then(_$LicenseExpiryDetailImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
equipmentId: null == equipmentId
|
||||
? _value.equipmentId
|
||||
: equipmentId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
equipmentName: null == equipmentName
|
||||
? _value.equipmentName
|
||||
: equipmentName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
serialNumber: null == serialNumber
|
||||
? _value.serialNumber
|
||||
: serialNumber // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
companyName: null == companyName
|
||||
? _value.companyName
|
||||
: companyName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
licenseType: null == licenseType
|
||||
? _value.licenseType
|
||||
: licenseType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
startDate: null == startDate
|
||||
? _value.startDate
|
||||
: startDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
endDate: null == endDate
|
||||
? _value.endDate
|
||||
: endDate // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
daysRemaining: null == daysRemaining
|
||||
? _value.daysRemaining
|
||||
: daysRemaining // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isExpired: null == isExpired
|
||||
? _value.isExpired
|
||||
: isExpired // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$LicenseExpiryDetailImpl implements _LicenseExpiryDetail {
|
||||
const _$LicenseExpiryDetailImpl(
|
||||
{required this.id,
|
||||
@JsonKey(name: 'equipment_id') required this.equipmentId,
|
||||
@JsonKey(name: 'equipment_name') required this.equipmentName,
|
||||
@JsonKey(name: 'serial_number') required this.serialNumber,
|
||||
@JsonKey(name: 'company_name') required this.companyName,
|
||||
@JsonKey(name: 'license_type') required this.licenseType,
|
||||
@JsonKey(name: 'start_date') required this.startDate,
|
||||
@JsonKey(name: 'end_date') required this.endDate,
|
||||
@JsonKey(name: 'days_remaining') required this.daysRemaining,
|
||||
@JsonKey(name: 'is_expired') required this.isExpired});
|
||||
|
||||
factory _$LicenseExpiryDetailImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$LicenseExpiryDetailImplFromJson(json);
|
||||
|
||||
@override
|
||||
final int id;
|
||||
@override
|
||||
@JsonKey(name: 'equipment_id')
|
||||
final int equipmentId;
|
||||
@override
|
||||
@JsonKey(name: 'equipment_name')
|
||||
final String equipmentName;
|
||||
@override
|
||||
@JsonKey(name: 'serial_number')
|
||||
final String serialNumber;
|
||||
@override
|
||||
@JsonKey(name: 'company_name')
|
||||
final String companyName;
|
||||
@override
|
||||
@JsonKey(name: 'license_type')
|
||||
final String licenseType;
|
||||
@override
|
||||
@JsonKey(name: 'start_date')
|
||||
final String startDate;
|
||||
@override
|
||||
@JsonKey(name: 'end_date')
|
||||
final String endDate;
|
||||
@override
|
||||
@JsonKey(name: 'days_remaining')
|
||||
final int daysRemaining;
|
||||
@override
|
||||
@JsonKey(name: 'is_expired')
|
||||
final bool isExpired;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LicenseExpiryDetail(id: $id, equipmentId: $equipmentId, equipmentName: $equipmentName, serialNumber: $serialNumber, companyName: $companyName, licenseType: $licenseType, startDate: $startDate, endDate: $endDate, daysRemaining: $daysRemaining, isExpired: $isExpired)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LicenseExpiryDetailImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.equipmentId, equipmentId) ||
|
||||
other.equipmentId == equipmentId) &&
|
||||
(identical(other.equipmentName, equipmentName) ||
|
||||
other.equipmentName == equipmentName) &&
|
||||
(identical(other.serialNumber, serialNumber) ||
|
||||
other.serialNumber == serialNumber) &&
|
||||
(identical(other.companyName, companyName) ||
|
||||
other.companyName == companyName) &&
|
||||
(identical(other.licenseType, licenseType) ||
|
||||
other.licenseType == licenseType) &&
|
||||
(identical(other.startDate, startDate) ||
|
||||
other.startDate == startDate) &&
|
||||
(identical(other.endDate, endDate) || other.endDate == endDate) &&
|
||||
(identical(other.daysRemaining, daysRemaining) ||
|
||||
other.daysRemaining == daysRemaining) &&
|
||||
(identical(other.isExpired, isExpired) ||
|
||||
other.isExpired == isExpired));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
equipmentId,
|
||||
equipmentName,
|
||||
serialNumber,
|
||||
companyName,
|
||||
licenseType,
|
||||
startDate,
|
||||
endDate,
|
||||
daysRemaining,
|
||||
isExpired);
|
||||
|
||||
/// Create a copy of LicenseExpiryDetail
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LicenseExpiryDetailImplCopyWith<_$LicenseExpiryDetailImpl> get copyWith =>
|
||||
__$$LicenseExpiryDetailImplCopyWithImpl<_$LicenseExpiryDetailImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$LicenseExpiryDetailImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _LicenseExpiryDetail implements LicenseExpiryDetail {
|
||||
const factory _LicenseExpiryDetail(
|
||||
{required final int id,
|
||||
@JsonKey(name: 'equipment_id') required final int equipmentId,
|
||||
@JsonKey(name: 'equipment_name') required final String equipmentName,
|
||||
@JsonKey(name: 'serial_number') required final String serialNumber,
|
||||
@JsonKey(name: 'company_name') required final String companyName,
|
||||
@JsonKey(name: 'license_type') required final String licenseType,
|
||||
@JsonKey(name: 'start_date') required final String startDate,
|
||||
@JsonKey(name: 'end_date') required final String endDate,
|
||||
@JsonKey(name: 'days_remaining') required final int daysRemaining,
|
||||
@JsonKey(name: 'is_expired') required final bool isExpired}) =
|
||||
_$LicenseExpiryDetailImpl;
|
||||
|
||||
factory _LicenseExpiryDetail.fromJson(Map<String, dynamic> json) =
|
||||
_$LicenseExpiryDetailImpl.fromJson;
|
||||
|
||||
@override
|
||||
int get id;
|
||||
@override
|
||||
@JsonKey(name: 'equipment_id')
|
||||
int get equipmentId;
|
||||
@override
|
||||
@JsonKey(name: 'equipment_name')
|
||||
String get equipmentName;
|
||||
@override
|
||||
@JsonKey(name: 'serial_number')
|
||||
String get serialNumber;
|
||||
@override
|
||||
@JsonKey(name: 'company_name')
|
||||
String get companyName;
|
||||
@override
|
||||
@JsonKey(name: 'license_type')
|
||||
String get licenseType;
|
||||
@override
|
||||
@JsonKey(name: 'start_date')
|
||||
String get startDate;
|
||||
@override
|
||||
@JsonKey(name: 'end_date')
|
||||
String get endDate;
|
||||
@override
|
||||
@JsonKey(name: 'days_remaining')
|
||||
int get daysRemaining;
|
||||
@override
|
||||
@JsonKey(name: 'is_expired')
|
||||
bool get isExpired;
|
||||
|
||||
/// Create a copy of LicenseExpiryDetail
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LicenseExpiryDetailImplCopyWith<_$LicenseExpiryDetailImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
61
lib/data/models/dashboard/license_expiry_summary.g.dart
Normal file
61
lib/data/models/dashboard/license_expiry_summary.g.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'license_expiry_summary.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$LicenseExpirySummaryImpl _$$LicenseExpirySummaryImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$LicenseExpirySummaryImpl(
|
||||
within30Days: (json['within_30_days'] as num).toInt(),
|
||||
within60Days: (json['within_60_days'] as num).toInt(),
|
||||
within90Days: (json['within_90_days'] as num).toInt(),
|
||||
expired: (json['expired'] as num).toInt(),
|
||||
totalActive: (json['total_active'] as num).toInt(),
|
||||
licenses: (json['licenses'] as List<dynamic>)
|
||||
.map((e) => LicenseExpiryDetail.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$LicenseExpirySummaryImplToJson(
|
||||
_$LicenseExpirySummaryImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'within_30_days': instance.within30Days,
|
||||
'within_60_days': instance.within60Days,
|
||||
'within_90_days': instance.within90Days,
|
||||
'expired': instance.expired,
|
||||
'total_active': instance.totalActive,
|
||||
'licenses': instance.licenses,
|
||||
};
|
||||
|
||||
_$LicenseExpiryDetailImpl _$$LicenseExpiryDetailImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$LicenseExpiryDetailImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
equipmentId: (json['equipment_id'] as num).toInt(),
|
||||
equipmentName: json['equipment_name'] as String,
|
||||
serialNumber: json['serial_number'] as String,
|
||||
companyName: json['company_name'] as String,
|
||||
licenseType: json['license_type'] as String,
|
||||
startDate: json['start_date'] as String,
|
||||
endDate: json['end_date'] as String,
|
||||
daysRemaining: (json['days_remaining'] as num).toInt(),
|
||||
isExpired: json['is_expired'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$LicenseExpiryDetailImplToJson(
|
||||
_$LicenseExpiryDetailImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'equipment_id': instance.equipmentId,
|
||||
'equipment_name': instance.equipmentName,
|
||||
'serial_number': instance.serialNumber,
|
||||
'company_name': instance.companyName,
|
||||
'license_type': instance.licenseType,
|
||||
'start_date': instance.startDate,
|
||||
'end_date': instance.endDate,
|
||||
'days_remaining': instance.daysRemaining,
|
||||
'is_expired': instance.isExpired,
|
||||
};
|
||||
35
lib/data/models/lookups/lookup_data.dart
Normal file
35
lib/data/models/lookups/lookup_data.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'lookup_data.freezed.dart';
|
||||
part 'lookup_data.g.dart';
|
||||
|
||||
@freezed
|
||||
class LookupData with _$LookupData {
|
||||
const factory LookupData({
|
||||
@JsonKey(name: 'equipment_types') required List<LookupItem> equipmentTypes,
|
||||
@JsonKey(name: 'equipment_statuses') required List<LookupItem> equipmentStatuses,
|
||||
@JsonKey(name: 'license_types') required List<LookupItem> licenseTypes,
|
||||
@JsonKey(name: 'manufacturers') required List<LookupItem> manufacturers,
|
||||
@JsonKey(name: 'user_roles') required List<LookupItem> userRoles,
|
||||
@JsonKey(name: 'company_statuses') required List<LookupItem> companyStatuses,
|
||||
@JsonKey(name: 'warehouse_types') required List<LookupItem> warehouseTypes,
|
||||
}) = _LookupData;
|
||||
|
||||
factory LookupData.fromJson(Map<String, dynamic> json) =>
|
||||
_$LookupDataFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class LookupItem with _$LookupItem {
|
||||
const factory LookupItem({
|
||||
required String code,
|
||||
required String name,
|
||||
String? description,
|
||||
@JsonKey(name: 'display_order') int? displayOrder,
|
||||
@JsonKey(name: 'is_active') @Default(true) bool isActive,
|
||||
Map<String, dynamic>? metadata,
|
||||
}) = _LookupItem;
|
||||
|
||||
factory LookupItem.fromJson(Map<String, dynamic> json) =>
|
||||
_$LookupItemFromJson(json);
|
||||
}
|
||||
656
lib/data/models/lookups/lookup_data.freezed.dart
Normal file
656
lib/data/models/lookups/lookup_data.freezed.dart
Normal file
@@ -0,0 +1,656 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'lookup_data.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
LookupData _$LookupDataFromJson(Map<String, dynamic> json) {
|
||||
return _LookupData.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LookupData {
|
||||
@JsonKey(name: 'equipment_types')
|
||||
List<LookupItem> get equipmentTypes => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'equipment_statuses')
|
||||
List<LookupItem> get equipmentStatuses => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'license_types')
|
||||
List<LookupItem> get licenseTypes => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'manufacturers')
|
||||
List<LookupItem> get manufacturers => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'user_roles')
|
||||
List<LookupItem> get userRoles => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'company_statuses')
|
||||
List<LookupItem> get companyStatuses => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'warehouse_types')
|
||||
List<LookupItem> get warehouseTypes => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this LookupData to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LookupData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$LookupDataCopyWith<LookupData> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LookupDataCopyWith<$Res> {
|
||||
factory $LookupDataCopyWith(
|
||||
LookupData value, $Res Function(LookupData) then) =
|
||||
_$LookupDataCopyWithImpl<$Res, LookupData>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'equipment_types') List<LookupItem> equipmentTypes,
|
||||
@JsonKey(name: 'equipment_statuses') List<LookupItem> equipmentStatuses,
|
||||
@JsonKey(name: 'license_types') List<LookupItem> licenseTypes,
|
||||
@JsonKey(name: 'manufacturers') List<LookupItem> manufacturers,
|
||||
@JsonKey(name: 'user_roles') List<LookupItem> userRoles,
|
||||
@JsonKey(name: 'company_statuses') List<LookupItem> companyStatuses,
|
||||
@JsonKey(name: 'warehouse_types') List<LookupItem> warehouseTypes});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LookupDataCopyWithImpl<$Res, $Val extends LookupData>
|
||||
implements $LookupDataCopyWith<$Res> {
|
||||
_$LookupDataCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LookupData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? equipmentTypes = null,
|
||||
Object? equipmentStatuses = null,
|
||||
Object? licenseTypes = null,
|
||||
Object? manufacturers = null,
|
||||
Object? userRoles = null,
|
||||
Object? companyStatuses = null,
|
||||
Object? warehouseTypes = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
equipmentTypes: null == equipmentTypes
|
||||
? _value.equipmentTypes
|
||||
: equipmentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
equipmentStatuses: null == equipmentStatuses
|
||||
? _value.equipmentStatuses
|
||||
: equipmentStatuses // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
licenseTypes: null == licenseTypes
|
||||
? _value.licenseTypes
|
||||
: licenseTypes // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
manufacturers: null == manufacturers
|
||||
? _value.manufacturers
|
||||
: manufacturers // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
userRoles: null == userRoles
|
||||
? _value.userRoles
|
||||
: userRoles // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
companyStatuses: null == companyStatuses
|
||||
? _value.companyStatuses
|
||||
: companyStatuses // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
warehouseTypes: null == warehouseTypes
|
||||
? _value.warehouseTypes
|
||||
: warehouseTypes // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LookupDataImplCopyWith<$Res>
|
||||
implements $LookupDataCopyWith<$Res> {
|
||||
factory _$$LookupDataImplCopyWith(
|
||||
_$LookupDataImpl value, $Res Function(_$LookupDataImpl) then) =
|
||||
__$$LookupDataImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'equipment_types') List<LookupItem> equipmentTypes,
|
||||
@JsonKey(name: 'equipment_statuses') List<LookupItem> equipmentStatuses,
|
||||
@JsonKey(name: 'license_types') List<LookupItem> licenseTypes,
|
||||
@JsonKey(name: 'manufacturers') List<LookupItem> manufacturers,
|
||||
@JsonKey(name: 'user_roles') List<LookupItem> userRoles,
|
||||
@JsonKey(name: 'company_statuses') List<LookupItem> companyStatuses,
|
||||
@JsonKey(name: 'warehouse_types') List<LookupItem> warehouseTypes});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LookupDataImplCopyWithImpl<$Res>
|
||||
extends _$LookupDataCopyWithImpl<$Res, _$LookupDataImpl>
|
||||
implements _$$LookupDataImplCopyWith<$Res> {
|
||||
__$$LookupDataImplCopyWithImpl(
|
||||
_$LookupDataImpl _value, $Res Function(_$LookupDataImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of LookupData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? equipmentTypes = null,
|
||||
Object? equipmentStatuses = null,
|
||||
Object? licenseTypes = null,
|
||||
Object? manufacturers = null,
|
||||
Object? userRoles = null,
|
||||
Object? companyStatuses = null,
|
||||
Object? warehouseTypes = null,
|
||||
}) {
|
||||
return _then(_$LookupDataImpl(
|
||||
equipmentTypes: null == equipmentTypes
|
||||
? _value._equipmentTypes
|
||||
: equipmentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
equipmentStatuses: null == equipmentStatuses
|
||||
? _value._equipmentStatuses
|
||||
: equipmentStatuses // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
licenseTypes: null == licenseTypes
|
||||
? _value._licenseTypes
|
||||
: licenseTypes // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
manufacturers: null == manufacturers
|
||||
? _value._manufacturers
|
||||
: manufacturers // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
userRoles: null == userRoles
|
||||
? _value._userRoles
|
||||
: userRoles // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
companyStatuses: null == companyStatuses
|
||||
? _value._companyStatuses
|
||||
: companyStatuses // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
warehouseTypes: null == warehouseTypes
|
||||
? _value._warehouseTypes
|
||||
: warehouseTypes // ignore: cast_nullable_to_non_nullable
|
||||
as List<LookupItem>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$LookupDataImpl implements _LookupData {
|
||||
const _$LookupDataImpl(
|
||||
{@JsonKey(name: 'equipment_types')
|
||||
required final List<LookupItem> equipmentTypes,
|
||||
@JsonKey(name: 'equipment_statuses')
|
||||
required final List<LookupItem> equipmentStatuses,
|
||||
@JsonKey(name: 'license_types')
|
||||
required final List<LookupItem> licenseTypes,
|
||||
@JsonKey(name: 'manufacturers')
|
||||
required final List<LookupItem> manufacturers,
|
||||
@JsonKey(name: 'user_roles') required final List<LookupItem> userRoles,
|
||||
@JsonKey(name: 'company_statuses')
|
||||
required final List<LookupItem> companyStatuses,
|
||||
@JsonKey(name: 'warehouse_types')
|
||||
required final List<LookupItem> warehouseTypes})
|
||||
: _equipmentTypes = equipmentTypes,
|
||||
_equipmentStatuses = equipmentStatuses,
|
||||
_licenseTypes = licenseTypes,
|
||||
_manufacturers = manufacturers,
|
||||
_userRoles = userRoles,
|
||||
_companyStatuses = companyStatuses,
|
||||
_warehouseTypes = warehouseTypes;
|
||||
|
||||
factory _$LookupDataImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$LookupDataImplFromJson(json);
|
||||
|
||||
final List<LookupItem> _equipmentTypes;
|
||||
@override
|
||||
@JsonKey(name: 'equipment_types')
|
||||
List<LookupItem> get equipmentTypes {
|
||||
if (_equipmentTypes is EqualUnmodifiableListView) return _equipmentTypes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_equipmentTypes);
|
||||
}
|
||||
|
||||
final List<LookupItem> _equipmentStatuses;
|
||||
@override
|
||||
@JsonKey(name: 'equipment_statuses')
|
||||
List<LookupItem> get equipmentStatuses {
|
||||
if (_equipmentStatuses is EqualUnmodifiableListView)
|
||||
return _equipmentStatuses;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_equipmentStatuses);
|
||||
}
|
||||
|
||||
final List<LookupItem> _licenseTypes;
|
||||
@override
|
||||
@JsonKey(name: 'license_types')
|
||||
List<LookupItem> get licenseTypes {
|
||||
if (_licenseTypes is EqualUnmodifiableListView) return _licenseTypes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_licenseTypes);
|
||||
}
|
||||
|
||||
final List<LookupItem> _manufacturers;
|
||||
@override
|
||||
@JsonKey(name: 'manufacturers')
|
||||
List<LookupItem> get manufacturers {
|
||||
if (_manufacturers is EqualUnmodifiableListView) return _manufacturers;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_manufacturers);
|
||||
}
|
||||
|
||||
final List<LookupItem> _userRoles;
|
||||
@override
|
||||
@JsonKey(name: 'user_roles')
|
||||
List<LookupItem> get userRoles {
|
||||
if (_userRoles is EqualUnmodifiableListView) return _userRoles;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_userRoles);
|
||||
}
|
||||
|
||||
final List<LookupItem> _companyStatuses;
|
||||
@override
|
||||
@JsonKey(name: 'company_statuses')
|
||||
List<LookupItem> get companyStatuses {
|
||||
if (_companyStatuses is EqualUnmodifiableListView) return _companyStatuses;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_companyStatuses);
|
||||
}
|
||||
|
||||
final List<LookupItem> _warehouseTypes;
|
||||
@override
|
||||
@JsonKey(name: 'warehouse_types')
|
||||
List<LookupItem> get warehouseTypes {
|
||||
if (_warehouseTypes is EqualUnmodifiableListView) return _warehouseTypes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_warehouseTypes);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LookupData(equipmentTypes: $equipmentTypes, equipmentStatuses: $equipmentStatuses, licenseTypes: $licenseTypes, manufacturers: $manufacturers, userRoles: $userRoles, companyStatuses: $companyStatuses, warehouseTypes: $warehouseTypes)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LookupDataImpl &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._equipmentTypes, _equipmentTypes) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._equipmentStatuses, _equipmentStatuses) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._licenseTypes, _licenseTypes) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._manufacturers, _manufacturers) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._userRoles, _userRoles) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._companyStatuses, _companyStatuses) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._warehouseTypes, _warehouseTypes));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_equipmentTypes),
|
||||
const DeepCollectionEquality().hash(_equipmentStatuses),
|
||||
const DeepCollectionEquality().hash(_licenseTypes),
|
||||
const DeepCollectionEquality().hash(_manufacturers),
|
||||
const DeepCollectionEquality().hash(_userRoles),
|
||||
const DeepCollectionEquality().hash(_companyStatuses),
|
||||
const DeepCollectionEquality().hash(_warehouseTypes));
|
||||
|
||||
/// Create a copy of LookupData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LookupDataImplCopyWith<_$LookupDataImpl> get copyWith =>
|
||||
__$$LookupDataImplCopyWithImpl<_$LookupDataImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$LookupDataImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _LookupData implements LookupData {
|
||||
const factory _LookupData(
|
||||
{@JsonKey(name: 'equipment_types')
|
||||
required final List<LookupItem> equipmentTypes,
|
||||
@JsonKey(name: 'equipment_statuses')
|
||||
required final List<LookupItem> equipmentStatuses,
|
||||
@JsonKey(name: 'license_types')
|
||||
required final List<LookupItem> licenseTypes,
|
||||
@JsonKey(name: 'manufacturers')
|
||||
required final List<LookupItem> manufacturers,
|
||||
@JsonKey(name: 'user_roles') required final List<LookupItem> userRoles,
|
||||
@JsonKey(name: 'company_statuses')
|
||||
required final List<LookupItem> companyStatuses,
|
||||
@JsonKey(name: 'warehouse_types')
|
||||
required final List<LookupItem> warehouseTypes}) = _$LookupDataImpl;
|
||||
|
||||
factory _LookupData.fromJson(Map<String, dynamic> json) =
|
||||
_$LookupDataImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'equipment_types')
|
||||
List<LookupItem> get equipmentTypes;
|
||||
@override
|
||||
@JsonKey(name: 'equipment_statuses')
|
||||
List<LookupItem> get equipmentStatuses;
|
||||
@override
|
||||
@JsonKey(name: 'license_types')
|
||||
List<LookupItem> get licenseTypes;
|
||||
@override
|
||||
@JsonKey(name: 'manufacturers')
|
||||
List<LookupItem> get manufacturers;
|
||||
@override
|
||||
@JsonKey(name: 'user_roles')
|
||||
List<LookupItem> get userRoles;
|
||||
@override
|
||||
@JsonKey(name: 'company_statuses')
|
||||
List<LookupItem> get companyStatuses;
|
||||
@override
|
||||
@JsonKey(name: 'warehouse_types')
|
||||
List<LookupItem> get warehouseTypes;
|
||||
|
||||
/// Create a copy of LookupData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LookupDataImplCopyWith<_$LookupDataImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
LookupItem _$LookupItemFromJson(Map<String, dynamic> json) {
|
||||
return _LookupItem.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LookupItem {
|
||||
String get code => throw _privateConstructorUsedError;
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
String? get description => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'display_order')
|
||||
int? get displayOrder => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'is_active')
|
||||
bool get isActive => throw _privateConstructorUsedError;
|
||||
Map<String, dynamic>? get metadata => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this LookupItem to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LookupItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$LookupItemCopyWith<LookupItem> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LookupItemCopyWith<$Res> {
|
||||
factory $LookupItemCopyWith(
|
||||
LookupItem value, $Res Function(LookupItem) then) =
|
||||
_$LookupItemCopyWithImpl<$Res, LookupItem>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String code,
|
||||
String name,
|
||||
String? description,
|
||||
@JsonKey(name: 'display_order') int? displayOrder,
|
||||
@JsonKey(name: 'is_active') bool isActive,
|
||||
Map<String, dynamic>? metadata});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LookupItemCopyWithImpl<$Res, $Val extends LookupItem>
|
||||
implements $LookupItemCopyWith<$Res> {
|
||||
_$LookupItemCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LookupItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? code = null,
|
||||
Object? name = null,
|
||||
Object? description = freezed,
|
||||
Object? displayOrder = freezed,
|
||||
Object? isActive = null,
|
||||
Object? metadata = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
code: null == code
|
||||
? _value.code
|
||||
: code // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
description: freezed == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
displayOrder: freezed == displayOrder
|
||||
? _value.displayOrder
|
||||
: displayOrder // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
isActive: null == isActive
|
||||
? _value.isActive
|
||||
: isActive // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
metadata: freezed == metadata
|
||||
? _value.metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LookupItemImplCopyWith<$Res>
|
||||
implements $LookupItemCopyWith<$Res> {
|
||||
factory _$$LookupItemImplCopyWith(
|
||||
_$LookupItemImpl value, $Res Function(_$LookupItemImpl) then) =
|
||||
__$$LookupItemImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String code,
|
||||
String name,
|
||||
String? description,
|
||||
@JsonKey(name: 'display_order') int? displayOrder,
|
||||
@JsonKey(name: 'is_active') bool isActive,
|
||||
Map<String, dynamic>? metadata});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LookupItemImplCopyWithImpl<$Res>
|
||||
extends _$LookupItemCopyWithImpl<$Res, _$LookupItemImpl>
|
||||
implements _$$LookupItemImplCopyWith<$Res> {
|
||||
__$$LookupItemImplCopyWithImpl(
|
||||
_$LookupItemImpl _value, $Res Function(_$LookupItemImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of LookupItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? code = null,
|
||||
Object? name = null,
|
||||
Object? description = freezed,
|
||||
Object? displayOrder = freezed,
|
||||
Object? isActive = null,
|
||||
Object? metadata = freezed,
|
||||
}) {
|
||||
return _then(_$LookupItemImpl(
|
||||
code: null == code
|
||||
? _value.code
|
||||
: code // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
description: freezed == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
displayOrder: freezed == displayOrder
|
||||
? _value.displayOrder
|
||||
: displayOrder // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
isActive: null == isActive
|
||||
? _value.isActive
|
||||
: isActive // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
metadata: freezed == metadata
|
||||
? _value._metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$LookupItemImpl implements _LookupItem {
|
||||
const _$LookupItemImpl(
|
||||
{required this.code,
|
||||
required this.name,
|
||||
this.description,
|
||||
@JsonKey(name: 'display_order') this.displayOrder,
|
||||
@JsonKey(name: 'is_active') this.isActive = true,
|
||||
final Map<String, dynamic>? metadata})
|
||||
: _metadata = metadata;
|
||||
|
||||
factory _$LookupItemImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$LookupItemImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String code;
|
||||
@override
|
||||
final String name;
|
||||
@override
|
||||
final String? description;
|
||||
@override
|
||||
@JsonKey(name: 'display_order')
|
||||
final int? displayOrder;
|
||||
@override
|
||||
@JsonKey(name: 'is_active')
|
||||
final bool isActive;
|
||||
final Map<String, dynamic>? _metadata;
|
||||
@override
|
||||
Map<String, dynamic>? get metadata {
|
||||
final value = _metadata;
|
||||
if (value == null) return null;
|
||||
if (_metadata is EqualUnmodifiableMapView) return _metadata;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LookupItem(code: $code, name: $name, description: $description, displayOrder: $displayOrder, isActive: $isActive, metadata: $metadata)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LookupItemImpl &&
|
||||
(identical(other.code, code) || other.code == code) &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
(identical(other.description, description) ||
|
||||
other.description == description) &&
|
||||
(identical(other.displayOrder, displayOrder) ||
|
||||
other.displayOrder == displayOrder) &&
|
||||
(identical(other.isActive, isActive) ||
|
||||
other.isActive == isActive) &&
|
||||
const DeepCollectionEquality().equals(other._metadata, _metadata));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, code, name, description,
|
||||
displayOrder, isActive, const DeepCollectionEquality().hash(_metadata));
|
||||
|
||||
/// Create a copy of LookupItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LookupItemImplCopyWith<_$LookupItemImpl> get copyWith =>
|
||||
__$$LookupItemImplCopyWithImpl<_$LookupItemImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$LookupItemImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _LookupItem implements LookupItem {
|
||||
const factory _LookupItem(
|
||||
{required final String code,
|
||||
required final String name,
|
||||
final String? description,
|
||||
@JsonKey(name: 'display_order') final int? displayOrder,
|
||||
@JsonKey(name: 'is_active') final bool isActive,
|
||||
final Map<String, dynamic>? metadata}) = _$LookupItemImpl;
|
||||
|
||||
factory _LookupItem.fromJson(Map<String, dynamic> json) =
|
||||
_$LookupItemImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get code;
|
||||
@override
|
||||
String get name;
|
||||
@override
|
||||
String? get description;
|
||||
@override
|
||||
@JsonKey(name: 'display_order')
|
||||
int? get displayOrder;
|
||||
@override
|
||||
@JsonKey(name: 'is_active')
|
||||
bool get isActive;
|
||||
@override
|
||||
Map<String, dynamic>? get metadata;
|
||||
|
||||
/// Create a copy of LookupItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LookupItemImplCopyWith<_$LookupItemImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
63
lib/data/models/lookups/lookup_data.g.dart
Normal file
63
lib/data/models/lookups/lookup_data.g.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'lookup_data.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$LookupDataImpl _$$LookupDataImplFromJson(Map<String, dynamic> json) =>
|
||||
_$LookupDataImpl(
|
||||
equipmentTypes: (json['equipment_types'] as List<dynamic>)
|
||||
.map((e) => LookupItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
equipmentStatuses: (json['equipment_statuses'] as List<dynamic>)
|
||||
.map((e) => LookupItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
licenseTypes: (json['license_types'] as List<dynamic>)
|
||||
.map((e) => LookupItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
manufacturers: (json['manufacturers'] as List<dynamic>)
|
||||
.map((e) => LookupItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
userRoles: (json['user_roles'] as List<dynamic>)
|
||||
.map((e) => LookupItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
companyStatuses: (json['company_statuses'] as List<dynamic>)
|
||||
.map((e) => LookupItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
warehouseTypes: (json['warehouse_types'] as List<dynamic>)
|
||||
.map((e) => LookupItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$LookupDataImplToJson(_$LookupDataImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'equipment_types': instance.equipmentTypes,
|
||||
'equipment_statuses': instance.equipmentStatuses,
|
||||
'license_types': instance.licenseTypes,
|
||||
'manufacturers': instance.manufacturers,
|
||||
'user_roles': instance.userRoles,
|
||||
'company_statuses': instance.companyStatuses,
|
||||
'warehouse_types': instance.warehouseTypes,
|
||||
};
|
||||
|
||||
_$LookupItemImpl _$$LookupItemImplFromJson(Map<String, dynamic> json) =>
|
||||
_$LookupItemImpl(
|
||||
code: json['code'] as String,
|
||||
name: json['name'] as String,
|
||||
description: json['description'] as String?,
|
||||
displayOrder: (json['display_order'] as num?)?.toInt(),
|
||||
isActive: json['is_active'] as bool? ?? true,
|
||||
metadata: json['metadata'] as Map<String, dynamic>?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$LookupItemImplToJson(_$LookupItemImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'code': instance.code,
|
||||
'name': instance.name,
|
||||
'description': instance.description,
|
||||
'display_order': instance.displayOrder,
|
||||
'is_active': instance.isActive,
|
||||
'metadata': instance.metadata,
|
||||
};
|
||||
@@ -9,6 +9,7 @@ import '../data/datasources/remote/equipment_remote_datasource.dart';
|
||||
import '../data/datasources/remote/company_remote_datasource.dart';
|
||||
import '../data/datasources/remote/user_remote_datasource.dart';
|
||||
import '../data/datasources/remote/license_remote_datasource.dart';
|
||||
import '../data/datasources/remote/lookup_remote_datasource.dart';
|
||||
import '../data/datasources/remote/warehouse_remote_datasource.dart';
|
||||
import '../services/auth_service.dart';
|
||||
import '../services/dashboard_service.dart';
|
||||
@@ -16,6 +17,7 @@ import '../services/equipment_service.dart';
|
||||
import '../services/company_service.dart';
|
||||
import '../services/user_service.dart';
|
||||
import '../services/license_service.dart';
|
||||
import '../services/lookup_service.dart';
|
||||
import '../services/warehouse_service.dart';
|
||||
|
||||
/// GetIt 인스턴스
|
||||
@@ -52,6 +54,9 @@ Future<void> setupDependencies() async {
|
||||
getIt.registerLazySingleton<LicenseRemoteDataSource>(
|
||||
() => LicenseRemoteDataSourceImpl(apiClient: getIt()),
|
||||
);
|
||||
getIt.registerLazySingleton<LookupRemoteDataSource>(
|
||||
() => LookupRemoteDataSourceImpl(getIt()),
|
||||
);
|
||||
getIt.registerLazySingleton<WarehouseRemoteDataSource>(
|
||||
() => WarehouseRemoteDataSourceImpl(apiClient: getIt()),
|
||||
);
|
||||
@@ -75,6 +80,9 @@ Future<void> setupDependencies() async {
|
||||
getIt.registerLazySingleton<LicenseService>(
|
||||
() => LicenseService(getIt()),
|
||||
);
|
||||
getIt.registerLazySingleton<LookupService>(
|
||||
() => LookupService(getIt()),
|
||||
);
|
||||
getIt.registerLazySingleton<WarehouseService>(
|
||||
() => WarehouseService(),
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:superport/data/models/dashboard/equipment_status_distribution.dart';
|
||||
import 'package:superport/data/models/dashboard/expiring_license.dart';
|
||||
import 'package:superport/data/models/dashboard/license_expiry_summary.dart';
|
||||
import 'package:superport/data/models/dashboard/overview_stats.dart';
|
||||
import 'package:superport/data/models/dashboard/recent_activity.dart';
|
||||
import 'package:superport/services/dashboard_service.dart';
|
||||
@@ -17,35 +18,53 @@ class OverviewController extends ChangeNotifier {
|
||||
List<RecentActivity> _recentActivities = [];
|
||||
EquipmentStatusDistribution? _equipmentStatus;
|
||||
List<ExpiringLicense> _expiringLicenses = [];
|
||||
LicenseExpirySummary? _licenseExpirySummary;
|
||||
|
||||
// 로딩 상태
|
||||
bool _isLoadingStats = false;
|
||||
bool _isLoadingActivities = false;
|
||||
bool _isLoadingEquipmentStatus = false;
|
||||
bool _isLoadingLicenses = false;
|
||||
bool _isLoadingLicenseExpiry = false;
|
||||
|
||||
// 에러 상태
|
||||
String? _statsError;
|
||||
String? _activitiesError;
|
||||
String? _equipmentStatusError;
|
||||
String? _licensesError;
|
||||
String? _licenseExpiryError;
|
||||
|
||||
// Getters
|
||||
OverviewStats? get overviewStats => _overviewStats;
|
||||
List<RecentActivity> get recentActivities => _recentActivities;
|
||||
EquipmentStatusDistribution? get equipmentStatus => _equipmentStatus;
|
||||
List<ExpiringLicense> get expiringLicenses => _expiringLicenses;
|
||||
LicenseExpirySummary? get licenseExpirySummary => _licenseExpirySummary;
|
||||
|
||||
// 추가 getter
|
||||
int get totalCompanies => _overviewStats?.totalCompanies ?? 0;
|
||||
int get totalUsers => _overviewStats?.totalUsers ?? 0;
|
||||
|
||||
bool get isLoading => _isLoadingStats || _isLoadingActivities ||
|
||||
_isLoadingEquipmentStatus || _isLoadingLicenses;
|
||||
_isLoadingEquipmentStatus || _isLoadingLicenses ||
|
||||
_isLoadingLicenseExpiry;
|
||||
|
||||
String? get error {
|
||||
return _statsError ?? _activitiesError ??
|
||||
_equipmentStatusError ?? _licensesError;
|
||||
_equipmentStatusError ?? _licensesError ?? _licenseExpiryError;
|
||||
}
|
||||
|
||||
// 라이선스 만료 알림 여부
|
||||
bool get hasExpiringLicenses {
|
||||
if (_licenseExpirySummary == null) return false;
|
||||
return (_licenseExpirySummary!.within30Days > 0 ||
|
||||
_licenseExpirySummary!.expired > 0);
|
||||
}
|
||||
|
||||
// 긴급 라이선스 수 (30일 이내 또는 만료)
|
||||
int get urgentLicenseCount {
|
||||
if (_licenseExpirySummary == null) return 0;
|
||||
return _licenseExpirySummary!.within30Days + _licenseExpirySummary!.expired;
|
||||
}
|
||||
|
||||
OverviewController();
|
||||
@@ -58,6 +77,7 @@ class OverviewController extends ChangeNotifier {
|
||||
_loadRecentActivities(),
|
||||
_loadEquipmentStatus(),
|
||||
_loadExpiringLicenses(),
|
||||
_loadLicenseExpirySummary(),
|
||||
], eagerError: false); // 하나의 작업이 실패해도 다른 작업 계속 진행
|
||||
} catch (e) {
|
||||
DebugLogger.logError('대시보드 데이터 로드 중 오류', error: e);
|
||||
@@ -233,6 +253,38 @@ class OverviewController extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _loadLicenseExpirySummary() async {
|
||||
_isLoadingLicenseExpiry = true;
|
||||
_licenseExpiryError = null;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final result = await _dashboardService.getLicenseExpirySummary();
|
||||
|
||||
result.fold(
|
||||
(failure) {
|
||||
_licenseExpiryError = failure.message;
|
||||
DebugLogger.logError('라이선스 만료 요약 로드 실패', error: failure.message);
|
||||
},
|
||||
(summary) {
|
||||
_licenseExpirySummary = summary;
|
||||
DebugLogger.log('라이선스 만료 요약 로드 성공', tag: 'DASHBOARD', data: {
|
||||
'within30Days': summary.within30Days,
|
||||
'within60Days': summary.within60Days,
|
||||
'within90Days': summary.within90Days,
|
||||
'expired': summary.expired,
|
||||
});
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
_licenseExpiryError = '라이선스 만료 요약을 불러올 수 없습니다';
|
||||
DebugLogger.logError('라이선스 만료 요약 로드 예외', error: e);
|
||||
}
|
||||
|
||||
_isLoadingLicenseExpiry = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// 활동 타입별 아이콘과 색상 가져오기
|
||||
IconData getActivityIcon(String activityType) {
|
||||
switch (activityType.toLowerCase()) {
|
||||
|
||||
@@ -55,6 +55,12 @@ class _OverviewScreenRedesignState extends State<OverviewScreenRedesign> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 라이선스 만료 알림 배너 (조건부 표시)
|
||||
if (controller.hasExpiringLicenses) ...[
|
||||
_buildLicenseExpiryBanner(controller),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
|
||||
// 환영 섹션
|
||||
ShadcnCard(
|
||||
padding: const EdgeInsets.all(32),
|
||||
@@ -375,6 +381,82 @@ class _OverviewScreenRedesignState extends State<OverviewScreenRedesign> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLicenseExpiryBanner(OverviewController controller) {
|
||||
final summary = controller.licenseExpirySummary;
|
||||
if (summary == null) return const SizedBox.shrink();
|
||||
|
||||
Color bannerColor = ShadcnTheme.warning;
|
||||
String bannerText = '';
|
||||
IconData bannerIcon = Icons.warning_amber_rounded;
|
||||
|
||||
if (summary.expired > 0) {
|
||||
bannerColor = ShadcnTheme.destructive;
|
||||
bannerText = '${summary.expired}개 라이선스 만료';
|
||||
bannerIcon = Icons.error_outline;
|
||||
} else if (summary.within30Days > 0) {
|
||||
bannerColor = ShadcnTheme.warning;
|
||||
bannerText = '${summary.within30Days}개 라이선스 30일 내 만료 예정';
|
||||
bannerIcon = Icons.warning_amber_rounded;
|
||||
} else if (summary.within60Days > 0) {
|
||||
bannerColor = ShadcnTheme.primary;
|
||||
bannerText = '${summary.within60Days}개 라이선스 60일 내 만료 예정';
|
||||
bannerIcon = Icons.info_outline;
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: bannerColor.withValues(alpha: 0.1),
|
||||
border: Border.all(color: bannerColor.withValues(alpha: 0.3)),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(bannerIcon, color: bannerColor, size: 24),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'라이선스 관리 필요',
|
||||
style: ShadcnTheme.bodyMedium.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: bannerColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
bannerText,
|
||||
style: ShadcnTheme.bodySmall.copyWith(
|
||||
color: ShadcnTheme.foreground,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// 라이선스 목록 페이지로 이동
|
||||
Navigator.pushNamed(context, '/licenses');
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'상세 보기',
|
||||
style: TextStyle(color: bannerColor),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Icon(Icons.arrow_forward, color: bannerColor, size: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatCard(
|
||||
String title,
|
||||
String value,
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:superport/core/errors/failures.dart';
|
||||
import 'package:superport/data/datasources/remote/dashboard_remote_datasource.dart';
|
||||
import 'package:superport/data/models/dashboard/equipment_status_distribution.dart';
|
||||
import 'package:superport/data/models/dashboard/expiring_license.dart';
|
||||
import 'package:superport/data/models/dashboard/license_expiry_summary.dart';
|
||||
import 'package:superport/data/models/dashboard/overview_stats.dart';
|
||||
import 'package:superport/data/models/dashboard/recent_activity.dart';
|
||||
|
||||
@@ -12,6 +13,7 @@ abstract class DashboardService {
|
||||
Future<Either<Failure, List<RecentActivity>>> getRecentActivities();
|
||||
Future<Either<Failure, EquipmentStatusDistribution>> getEquipmentStatusDistribution();
|
||||
Future<Either<Failure, List<ExpiringLicense>>> getExpiringLicenses({int days = 30});
|
||||
Future<Either<Failure, LicenseExpirySummary>> getLicenseExpirySummary();
|
||||
}
|
||||
|
||||
@LazySingleton(as: DashboardService)
|
||||
@@ -39,4 +41,9 @@ class DashboardServiceImpl implements DashboardService {
|
||||
Future<Either<Failure, List<ExpiringLicense>>> getExpiringLicenses({int days = 30}) async {
|
||||
return await _remoteDataSource.getExpiringLicenses(days: days);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, LicenseExpirySummary>> getLicenseExpirySummary() async {
|
||||
return await _remoteDataSource.getLicenseExpirySummary();
|
||||
}
|
||||
}
|
||||
165
lib/services/lookup_service.dart
Normal file
165
lib/services/lookup_service.dart
Normal file
@@ -0,0 +1,165 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:superport/data/datasources/remote/lookup_remote_datasource.dart';
|
||||
import 'package:superport/data/models/lookups/lookup_data.dart';
|
||||
|
||||
@lazySingleton
|
||||
class LookupService extends ChangeNotifier {
|
||||
final LookupRemoteDataSource _dataSource;
|
||||
|
||||
LookupData? _lookupData;
|
||||
bool _isLoading = false;
|
||||
String? _error;
|
||||
DateTime? _lastFetchTime;
|
||||
|
||||
// 캐시 유효 시간 (30분)
|
||||
static const Duration _cacheValidDuration = Duration(minutes: 30);
|
||||
|
||||
LookupService(this._dataSource);
|
||||
|
||||
// Getters
|
||||
LookupData? get lookupData => _lookupData;
|
||||
bool get isLoading => _isLoading;
|
||||
String? get error => _error;
|
||||
bool get hasData => _lookupData != null;
|
||||
|
||||
// 캐시가 유효한지 확인
|
||||
bool get isCacheValid {
|
||||
if (_lastFetchTime == null) return false;
|
||||
return DateTime.now().difference(_lastFetchTime!) < _cacheValidDuration;
|
||||
}
|
||||
|
||||
// 장비 타입 목록
|
||||
List<LookupItem> get equipmentTypes => _lookupData?.equipmentTypes ?? [];
|
||||
|
||||
// 장비 상태 목록
|
||||
List<LookupItem> get equipmentStatuses => _lookupData?.equipmentStatuses ?? [];
|
||||
|
||||
// 라이선스 타입 목록
|
||||
List<LookupItem> get licenseTypes => _lookupData?.licenseTypes ?? [];
|
||||
|
||||
// 제조사 목록
|
||||
List<LookupItem> get manufacturers => _lookupData?.manufacturers ?? [];
|
||||
|
||||
// 사용자 역할 목록
|
||||
List<LookupItem> get userRoles => _lookupData?.userRoles ?? [];
|
||||
|
||||
// 회사 상태 목록
|
||||
List<LookupItem> get companyStatuses => _lookupData?.companyStatuses ?? [];
|
||||
|
||||
// 창고 타입 목록
|
||||
List<LookupItem> get warehouseTypes => _lookupData?.warehouseTypes ?? [];
|
||||
|
||||
// 전체 조회 데이터 로드
|
||||
Future<void> loadAllLookups({bool forceRefresh = false}) async {
|
||||
// 캐시가 유효하고 강제 새로고침이 아니면 캐시 사용
|
||||
if (!forceRefresh && isCacheValid && hasData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isLoading = true;
|
||||
_error = null;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final result = await _dataSource.getAllLookups();
|
||||
|
||||
result.fold(
|
||||
(failure) {
|
||||
_error = failure.message;
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
},
|
||||
(data) {
|
||||
_lookupData = data;
|
||||
_lastFetchTime = DateTime.now();
|
||||
_error = null;
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
_error = '조회 데이터 로드 중 오류가 발생했습니다: $e';
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// 특정 타입의 조회 데이터만 로드
|
||||
Future<Map<String, List<LookupItem>>?> loadLookupsByType(String type) async {
|
||||
try {
|
||||
final result = await _dataSource.getLookupsByType(type);
|
||||
|
||||
return result.fold(
|
||||
(failure) {
|
||||
_error = failure.message;
|
||||
notifyListeners();
|
||||
return null;
|
||||
},
|
||||
(data) {
|
||||
// 부분 업데이트 (필요한 경우)
|
||||
_updatePartialData(type, data);
|
||||
return data;
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
_error = '타입별 조회 데이터 로드 중 오류가 발생했습니다: $e';
|
||||
notifyListeners();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 부분 데이터 업데이트
|
||||
void _updatePartialData(String type, Map<String, List<LookupItem>> data) {
|
||||
if (_lookupData == null) {
|
||||
// 전체 데이터가 없으면 부분 데이터만으로 초기화
|
||||
_lookupData = LookupData(
|
||||
equipmentTypes: data['equipment_types'] ?? [],
|
||||
equipmentStatuses: data['equipment_statuses'] ?? [],
|
||||
licenseTypes: data['license_types'] ?? [],
|
||||
manufacturers: data['manufacturers'] ?? [],
|
||||
userRoles: data['user_roles'] ?? [],
|
||||
companyStatuses: data['company_statuses'] ?? [],
|
||||
warehouseTypes: data['warehouse_types'] ?? [],
|
||||
);
|
||||
} else {
|
||||
// 기존 데이터의 특정 부분만 업데이트
|
||||
_lookupData = _lookupData!.copyWith(
|
||||
equipmentTypes: data['equipment_types'] ?? _lookupData!.equipmentTypes,
|
||||
equipmentStatuses: data['equipment_statuses'] ?? _lookupData!.equipmentStatuses,
|
||||
licenseTypes: data['license_types'] ?? _lookupData!.licenseTypes,
|
||||
manufacturers: data['manufacturers'] ?? _lookupData!.manufacturers,
|
||||
userRoles: data['user_roles'] ?? _lookupData!.userRoles,
|
||||
companyStatuses: data['company_statuses'] ?? _lookupData!.companyStatuses,
|
||||
warehouseTypes: data['warehouse_types'] ?? _lookupData!.warehouseTypes,
|
||||
);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// 코드로 아이템 찾기
|
||||
LookupItem? findByCode(List<LookupItem> items, String code) {
|
||||
try {
|
||||
return items.firstWhere((item) => item.code == code);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 이름으로 아이템 찾기
|
||||
LookupItem? findByName(List<LookupItem> items, String name) {
|
||||
try {
|
||||
return items.firstWhere((item) => item.name == name);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 캐시 클리어
|
||||
void clearCache() {
|
||||
_lookupData = null;
|
||||
_lastFetchTime = null;
|
||||
_error = null;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
65
test/api_integration_test.dart
Normal file
65
test/api_integration_test.dart
Normal file
@@ -0,0 +1,65 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:superport/di/injection_container.dart';
|
||||
import 'package:superport/data/datasources/remote/dashboard_remote_datasource.dart';
|
||||
import 'package:superport/data/datasources/remote/lookup_remote_datasource.dart';
|
||||
import 'package:superport/services/lookup_service.dart';
|
||||
|
||||
void main() {
|
||||
setUpAll(() async {
|
||||
await setupDependencies();
|
||||
});
|
||||
|
||||
tearDownAll(() {
|
||||
GetIt.instance.reset();
|
||||
});
|
||||
|
||||
group('New API Integration Tests', () {
|
||||
test('DashboardRemoteDataSource should have getLicenseExpirySummary method', () {
|
||||
final dataSource = GetIt.instance<DashboardRemoteDataSource>();
|
||||
expect(dataSource, isNotNull);
|
||||
|
||||
// 메서드가 존재하는지 확인
|
||||
expect(dataSource.getLicenseExpirySummary, isA<Function>());
|
||||
});
|
||||
|
||||
test('LookupRemoteDataSource should be registered', () {
|
||||
final dataSource = GetIt.instance<LookupRemoteDataSource>();
|
||||
expect(dataSource, isNotNull);
|
||||
|
||||
// 메서드들이 존재하는지 확인
|
||||
expect(dataSource.getAllLookups, isA<Function>());
|
||||
expect(dataSource.getLookupsByType, isA<Function>());
|
||||
});
|
||||
|
||||
test('LookupService should be registered', () {
|
||||
final service = GetIt.instance<LookupService>();
|
||||
expect(service, isNotNull);
|
||||
|
||||
// 프로퍼티와 메서드 확인
|
||||
expect(service.hasData, isFalse); // 초기 상태
|
||||
expect(service.loadAllLookups, isA<Function>());
|
||||
expect(service.loadLookupsByType, isA<Function>());
|
||||
});
|
||||
|
||||
test('License expiry summary API endpoint should be callable', () async {
|
||||
final dataSource = GetIt.instance<DashboardRemoteDataSource>();
|
||||
|
||||
// API 호출 (실제 네트워크 호출이므로 실패할 수 있음)
|
||||
final result = await dataSource.getLicenseExpirySummary();
|
||||
|
||||
// Either 타입 확인
|
||||
expect(result.isLeft() || result.isRight(), isTrue);
|
||||
});
|
||||
|
||||
test('Lookups API endpoint should be callable', () async {
|
||||
final dataSource = GetIt.instance<LookupRemoteDataSource>();
|
||||
|
||||
// API 호출 (실제 네트워크 호출이므로 실패할 수 있음)
|
||||
final result = await dataSource.getAllLookups();
|
||||
|
||||
// Either 타입 확인
|
||||
expect(result.isLeft() || result.isRight(), isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user