Files
pfm-ocr/lib/features/documents/document_card.dart
T
fhanyuh caf8e98378 chore: normalize line endings (CRLF -> LF)
No content changes: git diff --ignore-all-space over these files is empty.
The churn came from editing on Windows against a repo checked out with LF.
2026-08-27 10:40:49 +07:00

164 lines
6.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../config/app_config.dart';
import '../../models/document_model.dart';
class DocumentCard extends StatelessWidget {
final DocumentModel doc;
final Future<void> Function(DocumentModel) onPrint;
final bool isUnsynced;
const DocumentCard({
super.key,
required this.doc,
required this.onPrint,
this.isUnsynced = false,
});
@override
Widget build(BuildContext context) {
final isProductScan = doc.docType == 'Product';
// Header category text
final categoryText = isProductScan
? (doc.items.isNotEmpty ? doc.items.first.namaBarang : 'Product Scan')
: (doc.namaPenerima.isNotEmpty ? doc.namaPenerima : 'Staff Toko');
// Category color: Product → green (primaryColor), DO → orange (doModeColor).
// doModeColor is the shared constant for the DO orange cue across the app
// (camera drawer, tab switcher, and here) — was an ad-hoc inline value.
final categoryColor = isProductScan ? AppConfig.primaryColor : AppConfig.doModeColor;
// Sync status badge (see docs/api-contract-map.md G6 - a document can be
// corrected locally after its PUT sync failed; the corrected copy is
// shown here, so the badge must reflect that it hasn't reached the
// server yet rather than always claiming "Terkonfirmasi").
final badgeLabel = isUnsynced ? 'Belum Tersinkron' : 'Terkonfirmasi';
final badgeColor = isUnsynced ? Colors.deepOrange : AppConfig.successColor;
// Bold title
final boldTitle = isProductScan
? doc.noDo
: doc.noPo;
// Subtitle text. Product Scan no longer links to a PO document (field
// removed - user request), so its subtitle is just the expiry date.
final subtitleText = isProductScan
? _formatDateString(doc.alamat.replaceAll("Product Scan: Expired ", ""))
: '${doc.tanggal} • ${doc.items.length} Item';
return Card(
elevation: 0,
margin: const EdgeInsets.only(bottom: AppConfig.spaceMedium),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConfig.borderRadiusMedium),
side: BorderSide(color: Colors.grey.shade200),
),
child: InkWell(
onTap: () => onPrint(doc),
borderRadius: BorderRadius.circular(AppConfig.borderRadiusMedium),
child: Padding(
padding: AppConfig.paddingLarge,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top category label
Text(
categoryText,
style: AppConfig.bodySmall.copyWith(
color: categoryColor,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: AppConfig.spaceXS),
// Large bold title
Text(
boldTitle,
style: AppConfig.bodyLarge.copyWith(
fontWeight: FontWeight.bold,
color: AppConfig.textPrimary,
fontSize: 16,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: AppConfig.spaceXS),
// Subtitle details
Text(
subtitleText,
style: AppConfig.bodyMedium.copyWith(
color: AppConfig.textSecondary,
fontSize: 13,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
const SizedBox(width: AppConfig.spaceMedium),
// Right column with status badge and print button
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// Status badge (Terkonfirmasi / Belum Tersinkron)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: badgeColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(AppConfig.borderRadiusSmall),
),
child: Text(
badgeLabel,
style: AppConfig.bodySmall.copyWith(
color: badgeColor,
fontWeight: FontWeight.bold,
fontSize: 11,
),
),
),
const SizedBox(height: AppConfig.spaceMedium),
// Print button styled as light-gray square container with print icon
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(AppConfig.borderRadiusSmall),
),
child: const Icon(
Icons.print,
size: 18,
color: AppConfig.textSecondary,
),
),
],
),
],
),
),
),
);
}
String _formatDateString(String input) {
try {
if (input.contains('/')) {
final parts = input.split('/');
if (parts.length == 3) {
final day = int.parse(parts[0]);
final month = int.parse(parts[1]);
final year = int.parse(parts[2]);
final date = DateTime(year, month, day);
return DateFormat('dd MMMM yyyy').format(date);
}
}
} catch (e) {
// Fallback
}
return input;
}
}