feat: 폼 필드 컴포넌트 분리 및 구독 카드 인터랙션 개선
- billing_cycle_selector, category_selector, currency_selector 컴포넌트 분리 - 구독 카드 클릭 이슈 해결을 위한 리팩토링 - SMS 스캔 화면 UI/UX 개선 및 기능 강화 - 상세 화면 컨트롤러 로직 개선 - 알림 서비스 및 구독 URL 매칭 기능 추가 - CLAUDE.md 프로젝트 가이드라인 대폭 확장 - 전반적인 코드 구조 개선 및 타입 안정성 강화 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -137,10 +137,7 @@ class NotificationService {
|
||||
// 각 구독에 대해 알림 재설정
|
||||
for (final subscription in subscriptions) {
|
||||
await schedulePaymentReminder(
|
||||
id: subscription.id.hashCode,
|
||||
serviceName: subscription.serviceName,
|
||||
amount: subscription.monthlyCost,
|
||||
billingDate: subscription.nextBillingDate,
|
||||
subscription: subscription,
|
||||
reminderDays: reminderDays,
|
||||
reminderHour: reminderHour,
|
||||
reminderMinute: reminderMinute,
|
||||
@@ -421,10 +418,7 @@ class NotificationService {
|
||||
}
|
||||
|
||||
static Future<void> schedulePaymentReminder({
|
||||
required int id,
|
||||
required String serviceName,
|
||||
required double amount,
|
||||
required DateTime billingDate,
|
||||
required SubscriptionModel subscription,
|
||||
int reminderDays = 3,
|
||||
int reminderHour = 10,
|
||||
int reminderMinute = 0,
|
||||
@@ -457,7 +451,7 @@ class NotificationService {
|
||||
|
||||
// 기본 알림 예약 (지정된 일수 전)
|
||||
final scheduledDate =
|
||||
billingDate.subtract(Duration(days: reminderDays)).copyWith(
|
||||
subscription.nextBillingDate.subtract(Duration(days: reminderDays)).copyWith(
|
||||
hour: reminderHour,
|
||||
minute: reminderMinute,
|
||||
second: 0,
|
||||
@@ -471,10 +465,27 @@ class NotificationService {
|
||||
daysText = '내일';
|
||||
}
|
||||
|
||||
// 이벤트 종료로 인한 가격 변동 확인
|
||||
String notificationBody;
|
||||
if (subscription.isEventActive &&
|
||||
subscription.eventEndDate != null &&
|
||||
subscription.eventEndDate!.isBefore(subscription.nextBillingDate) &&
|
||||
subscription.eventEndDate!.isAfter(DateTime.now())) {
|
||||
// 이벤트가 결제일 전에 종료되는 경우
|
||||
final eventPrice = subscription.eventPrice ?? subscription.monthlyCost;
|
||||
final normalPrice = subscription.monthlyCost;
|
||||
notificationBody = '${subscription.serviceName} 구독료 ${normalPrice.toStringAsFixed(0)}원이 $daysText 결제 예정입니다.\n'
|
||||
'⚠️ 이벤트 종료로 가격이 ${eventPrice.toStringAsFixed(0)}원에서 ${normalPrice.toStringAsFixed(0)}원으로 변경됩니다.';
|
||||
} else {
|
||||
// 일반 알림
|
||||
final currentPrice = subscription.currentPrice;
|
||||
notificationBody = '${subscription.serviceName} 구독료 ${currentPrice.toStringAsFixed(0)}원이 $daysText 결제 예정입니다.';
|
||||
}
|
||||
|
||||
await _notifications.zonedSchedule(
|
||||
id,
|
||||
subscription.id.hashCode,
|
||||
'구독 결제 예정 알림',
|
||||
'$serviceName 구독료 ${amount.toStringAsFixed(0)}원이 $daysText 결제 예정입니다.',
|
||||
notificationBody,
|
||||
tz.TZDateTime.from(scheduledDate, location),
|
||||
const NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
@@ -495,7 +506,7 @@ class NotificationService {
|
||||
if (isDailyReminder && reminderDays >= 2) {
|
||||
// 첫 번째 알림 다음 날부터 결제일 전날까지 매일 알림 예약
|
||||
for (int i = reminderDays - 1; i >= 1; i--) {
|
||||
final dailyDate = billingDate.subtract(Duration(days: i)).copyWith(
|
||||
final dailyDate = subscription.nextBillingDate.subtract(Duration(days: i)).copyWith(
|
||||
hour: reminderHour,
|
||||
minute: reminderMinute,
|
||||
second: 0,
|
||||
@@ -509,10 +520,25 @@ class NotificationService {
|
||||
remainingDaysText = '내일';
|
||||
}
|
||||
|
||||
// 각 날짜에 대한 이벤트 종료 확인
|
||||
String dailyNotificationBody;
|
||||
if (subscription.isEventActive &&
|
||||
subscription.eventEndDate != null &&
|
||||
subscription.eventEndDate!.isBefore(subscription.nextBillingDate) &&
|
||||
subscription.eventEndDate!.isAfter(DateTime.now())) {
|
||||
final eventPrice = subscription.eventPrice ?? subscription.monthlyCost;
|
||||
final normalPrice = subscription.monthlyCost;
|
||||
dailyNotificationBody = '${subscription.serviceName} 구독료 ${normalPrice.toStringAsFixed(0)}원이 $remainingDaysText 결제 예정입니다.\n'
|
||||
'⚠️ 이벤트 종료로 가격이 ${eventPrice.toStringAsFixed(0)}원에서 ${normalPrice.toStringAsFixed(0)}원으로 변경됩니다.';
|
||||
} else {
|
||||
final currentPrice = subscription.currentPrice;
|
||||
dailyNotificationBody = '${subscription.serviceName} 구독료 ${currentPrice.toStringAsFixed(0)}원이 $remainingDaysText 결제 예정입니다.';
|
||||
}
|
||||
|
||||
await _notifications.zonedSchedule(
|
||||
id + i, // 고유한 ID 생성을 위해 날짜 차이 더함
|
||||
subscription.id.hashCode + i, // 고유한 ID 생성을 위해 날짜 차이 더함
|
||||
'구독 결제 예정 알림',
|
||||
'$serviceName 구독료 ${amount.toStringAsFixed(0)}원이 $remainingDaysText 결제 예정입니다.',
|
||||
dailyNotificationBody,
|
||||
tz.TZDateTime.from(dailyDate, location),
|
||||
const NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
|
||||
Reference in New Issue
Block a user