전역 구조 리팩터링 및 테스트 확장
This commit is contained in:
@@ -1,25 +1,113 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import '../../../../../widgets/spec_page.dart';
|
||||
import '../../../../../core/constants/app_sections.dart';
|
||||
import '../../../../../widgets/app_layout.dart';
|
||||
import '../models/postal_search_result.dart';
|
||||
import '../widgets/postal_search_dialog.dart';
|
||||
|
||||
class PostalSearchPage extends StatelessWidget {
|
||||
class PostalSearchPage extends StatefulWidget {
|
||||
const PostalSearchPage({super.key});
|
||||
|
||||
@override
|
||||
State<PostalSearchPage> createState() => _PostalSearchPageState();
|
||||
}
|
||||
|
||||
class _PostalSearchPageState extends State<PostalSearchPage> {
|
||||
PostalSearchResult? _lastSelection;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const SpecPage(
|
||||
final theme = ShadTheme.of(context);
|
||||
|
||||
return AppLayout(
|
||||
title: '우편번호 검색',
|
||||
summary: '모달 기반 우편번호 검색 UI 구성을 정의합니다.',
|
||||
sections: [
|
||||
SpecSection(
|
||||
title: '모달 구성',
|
||||
items: [
|
||||
'검색어 [Text] 입력 필드',
|
||||
'결과 리스트: 우편번호 | 시도 | 시군구 | 도로명 | 건물번호',
|
||||
'선택 시 호출 화면에 우편번호/주소 전달',
|
||||
],
|
||||
),
|
||||
subtitle: '창고/고객사 등 주소 입력 폼에서 재사용되는 검색 모달입니다.',
|
||||
breadcrumbs: const [
|
||||
AppBreadcrumbItem(label: '대시보드', path: dashboardRoutePath),
|
||||
AppBreadcrumbItem(label: '유틸리티', path: '/utilities/postal-search'),
|
||||
AppBreadcrumbItem(label: '우편번호 검색'),
|
||||
],
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 520),
|
||||
child: ShadCard(
|
||||
title: Text('우편번호 검색 모달 미리보기', style: theme.textTheme.h3),
|
||||
description: Text(
|
||||
'검색 버튼을 눌러 모달 UI를 확인하세요. 검색 API 연동은 이후 단계에서 진행됩니다.',
|
||||
style: theme.textTheme.muted,
|
||||
),
|
||||
footer: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
ShadButton(
|
||||
leading: const Icon(LucideIcons.search, size: 16),
|
||||
onPressed: () async {
|
||||
final result = await showPostalSearchDialog(context);
|
||||
if (result != null && mounted) {
|
||||
setState(() {
|
||||
_lastSelection = result;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: const Text('모달 열기'),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'우편번호를 검색한 뒤 결과 행을 클릭하면 선택한 주소가 폼에 채워집니다.',
|
||||
style: theme.textTheme.p,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (_lastSelection == null)
|
||||
Text('선택한 주소가 없습니다.', style: theme.textTheme.muted)
|
||||
else
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: theme.colorScheme.border),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'선택된 우편번호',
|
||||
style: theme.textTheme.small.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
_lastSelection!.zipcode,
|
||||
style: theme.textTheme.h4,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'주소 구성요소',
|
||||
style: theme.textTheme.small.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
_lastSelection!.fullAddress.isEmpty
|
||||
? '주소 정보가 제공되지 않았습니다.'
|
||||
: _lastSelection!.fullAddress,
|
||||
style: theme.textTheme.p,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,7 +255,14 @@ class _PostalSearchDialogState extends State<_PostalSearchDialog> {
|
||||
],
|
||||
],
|
||||
onRowTap: (index) {
|
||||
navigator.pop(_results[index]);
|
||||
if (_results.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final adjustedIndex = (index - 1).clamp(
|
||||
0,
|
||||
_results.length - 1,
|
||||
);
|
||||
navigator.pop(_results[adjustedIndex]);
|
||||
},
|
||||
emptyLabel: '검색 결과가 없습니다.',
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user