Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: 이용약관 페이지 추가를 위한 상품 탭 레이아웃 수정 #18

Merged
merged 3 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/common/main_navigation_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import 'package:tuti/features/profile/views/profile_screen.dart';
import 'package:tuti/features/tutis/views/tuti_screen.dart';
import 'package:tuti/features/tutis/widgets/tuti_widgets/tuti_login_dialog.dart';

import '../features/tutis/views/personal_branding_screen.dart';
import '../features/tutis/views/s_personal_branding.dart';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

디렉토리에서 파일을 찾을 때 이름을 찾는데 시간을 줄이기 위해 screen 파일은 앞글자를 따 s로 통일 시킬 예정입니다.


class MainNavigationScreen extends ConsumerStatefulWidget {
static const routeName = 'mainNavigation';
Expand Down
21 changes: 21 additions & 0 deletions lib/constants/string.dart
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

카카오페이 가맹점 신청을 위해 임시로 데이터를 사용했습니다. 추후 서버에서 받아와 뿌릴 예정입니다.

Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,24 @@ final daysConstant = [
'토',
'일',
];

const String termsOfUseContents =
'트티는 회원에게 콘텐츠, 상품 등을 제공하는 서비스 플랫폼입니다. 회원은 컴퓨터, 휴대전화 등 정보통신기기를 사용하여 트티가 회원에게 제공하는 서비스(이하 “서비스”)를 이용할 수 있으며, 서비스의 구체적인 내용과 이용 조건을 이용약관 및 정책, 서비스 페이지 등에서 확인할 수 있습니다.\n이용약관(이하 ”이 약관”)은 서비스 이용과 관련하여 트티와 회원 간의 권리와 의무에 대한 내용을 담고 있습니다.\n1. 계정\n1.1 회원가입\n서비스를 이용하기 위해서는 회원가입에 의하여 생성되는 계정이 필요합니다. 이와 관련하여 트티는 회원에 대한 본인 인증 절차를 진행할 수 있으며, 회원이 회원가입에 필요한 정보 제공을 거절하거나 타인 정보 또는 허위 정보를 입력하는 경우 회원가입이 진행되지 않을 수 있습니다.';
const String minorContents =
'\n1.2 미성년자\n미성년자는 관련 법령에 따라 회원가입 또는 서비스이용이 제한될 수 있으며, 부모 등 법정대리인의 동의를 얻은 후 서비스이용을 위한 결제를 진행하여야 합니다. 다만 법정대리인이 동의하지 아니한 경우, 미성년자 본인 또는 법정대리인은 결제를 취소할 수 있습니다.\n';
const String updateOfAccountInfo =
'1.3 계정정보의 갱신\n전자우편주소, 연락처 등 계정정보가 변경된 경우 이를 반영하는 것은 회원의 책임이며 트티의 고의 또는 과실이 없음에도 불구하고 계정정보를 갱신하지 아니하여 발생하는 불이익은 회원이 부담합니다.';
const String privacyPolicyIntroContents =
'주식회사 이쿠아(이하"회사")는 『개인정보 보호법』 및 관련 법령상의 개인정보 보호규정을 준수하며, 『개인정보 보호법』에 의거한 개인정보 처리방침을 정하여 이용자 권익보호에 최선을 다하고 있습니다.\n회사는 개인정보 처리방침을 통하여 회사가 이용자로부터 제공받은 개인정보를 어떠한 용도와 방식으로 이용하고 있으며, 개인정보보호를 위해 어떠한 조치를 취하고 있는지 알려드립니다.\n';
const String privacyPolicyTableOfContents =
'1. 개인정보의 처리 목적\n2. 개인정보의 처리 및 보유기간\n3. 처리하는 개인정보의 항목\n';
const String privacyPolicyPurposeOfProcessingPersonalInfo =
'1. 개인정보의 처리 목적\n회사는 다음의 목적을 위하여 개인정보를 처리합니다.\n① 회원 가입 및 관리\n- 회원제 서비스 이용에 따른 본인 식별, 회원자격 유지ㆍ관리, 서비스 부정이용 방지와 비인가 사용방지, 각종 고지ㆍ통지, 불만처리 및 고객상담 등 민원 처리, 분쟁 조정을 위한 기록보존\n② 재화 또는 서비스 제공\n - 서비스 제공에 관한 계약 이행 및 서비스 제공에 따른 요금정산, 콘텐츠 제공, 구매 및 요금 결제, 환불, 물품배송, 본인인증, 요금추심\n③ 서비스 개선 및 마케팅 활용\n- 신규 서비스(제품) 개발 및 특화, 이벤트 등 홍보성 정보 전달    - 인구통계학적 특성에 따른 서비스 제공 및 광고 게재, 접속 빈도 파악, 회원의 서비스 이용에 대한 통계 분석\n';
const String privacyPolicyProcessingRetentionPeriodOfPersonalInfo =
'2. 개인정보의 처리 및 보유기간\n회사는 원칙적으로 개인정보 수집 및 이용목적이 달성된 후에는 해당 정보를 지체없이 파기합니다. 다만, 관계법령의 규정에 의하여 보존할 필요가 있는 경우, 회사는 아래와 같이 관계법령에서 정한 일정한 기간 동안 회원정보를 보관하며, 이 경우 회사는 해당 개인정보를 분리하여 보관합니다.\n';
const String refundPolicyServiceOfSales =
'1. 판매 서비스\n구입한 날로부터 7일 이내 이용한 경우 : 결제 대금 전액\n구입한 날로부터 14일 이내 이용한 경우 : 결제 대금의 5/10\n구입한 날로부터 21일 이내 이용한 경우 : 결제 대금의 2/10\n구입한 날로부터 30일 이후 : 없음\n';
const String refundPolicyCoachingRights =
'2. 코칭권\n코칭권 이용기간 만료 전 : 결제대금 전액\n코칭권 이용기간 만료 후 : 환불 불가\n-코칭권 이용기간은 구매 당시 부여된 기간을 기준으로 합니다.';
const String refundPolicyInquiry =
'트티 서비스와 관련하여 궁금하신 사항이 있으시면\n고객센터(대표번호: 010-7415-8850 / 이메일: [email protected] (평일 10:00~18:00 )로 문의 주시기 바랍니다 ';
17 changes: 17 additions & 0 deletions lib/features/tutis/models/company_info.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:flutter/material.dart';

class CompanyInfo {
final String title;
final String contents;
final String? subTitle;
final String? subContents;
final VoidCallback onTap;

const CompanyInfo({
required this.title,
required this.contents,
this.subContents,
this.subTitle,
required this.onTap,
});
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

회사 관련 정보 객체를 만들어줬습니다.

일단은 회사 소개 관련 카드를 봤을 때 title, contents, subtitle, subcontents, ontap 메서드로 분해가 되어 이렇게 설정했습니다.

}
59 changes: 0 additions & 59 deletions lib/features/tutis/views/personal_branding_screen.dart

This file was deleted.

112 changes: 112 additions & 0 deletions lib/features/tutis/views/s_personal_branding.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:go_router/go_router.dart';
import 'package:tuti/common/constraints_scaffold.dart';
import 'package:tuti/common/service/goods_provider.dart';
import 'package:tuti/common/tuti_text.dart';
import 'package:tuti/constants/color.dart';
import 'package:tuti/features/tutis/models/company_info.dart';
import 'package:tuti/features/tutis/models/goods.dart';
import 'package:tuti/features/tutis/views/goods_detail_screen.dart';
import 'package:tuti/features/tutis/views/s_terms_of_use.dart';
import 'package:tuti/features/tutis/widgets/tuti_widgets/goods_container.dart';
import 'package:tuti/features/tutis/widgets/tuti_widgets/main_banner.dart';
import 'package:tuti/features/tutis/widgets/tuti_widgets/w_company_info_card.dart';
import 'package:universal_html/js.dart';
import 'package:url_launcher/url_launcher.dart';

class PersonalBrandingScreen extends ConsumerWidget {
const PersonalBrandingScreen({super.key});

static const String routeName = "personalBranding";
static const String routePath = "/personalBranding";

@override
Widget build(BuildContext context, WidgetRef ref) {
final goodsList = ref.watch(goodsProvider);
CompanyInfo companyInfo = CompanyInfo(
title: '트티',
contents: '기업명: (주) 이쿠아\n 주소: 서울 강남구 테헤란로22길 15 2층\n 전화: 010.7415.8850',
onTap: () {
String urlPath = 'info.tuti20.com';
launchUrl(
Uri.parse(urlPath),
);
},
);
CompanyInfo customerCenter = CompanyInfo(
title: '고객센터',
contents: '오전 10 ~ 오후 6시(주말, 공휴일 제외)\n문의하기: 010.7415.8850',
subContents: '이용약관\n\n환불 정책\n\n제휴 및 대외협력',
subTitle: '개인정보처리방침',
onTap: () {
context.push(TermsOfUseScreen.routePath);
},
);

List<CompanyInfo> companyInfos = [companyInfo, customerCenter];
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

회사 정보 객체를 담은 배열 생성해주었고 이를 매핑하여 회사 정보 관련 카드를 동적으로 생성합니다.


return ConstraintsScaffold(
child: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
expandedHeight: 130.h,
floating: false,
pinned: false,
flexibleSpace: FlexibleSpaceBar(
background: TuTiBanner(
onTap: () {},
margin: EdgeInsets.only(
top: 35.h, bottom: 15.h, left: 40.w, right: 40.w),
title: '오직, 트티에서만 제공하는\n2024년 당신의 커리어 고민 해결 솔루션.',
subtitle: '체계적이고 알찬 개인 맞춤형 레벨업!',
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
childCount:
goodsList.value?.length ?? 0, // Handle null values gracefully
(context, index) {
if (goodsList.hasValue) {
return GoodsContainer(
name: goodsList.value![index].name,
discountRate: goodsList.value![index].discountRate,
regularPrice: goodsList.value![index].regularPrice,
discountedPrice: goodsList.value![index].discountedPrice,
discountPolicy: goodsList.value![index].discountPolicy,
);
} else if (goodsList.hasError) {
return SliverToBoxAdapter(
child: Text('Error: ${goodsList.error}'),
);
} else {
return const SliverToBoxAdapter(
child: CircularProgressIndicator(),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List형식으로 상품 컨테이너가 생성되고 있고 상품 컨테이너가 사용하는 Goods 정보는 서버에서 받아오는 AsyncValue 객체이기 때문에 이를 handle하기 위해 hasValue, hasError, else로 분기를 나눠 처리해습니다.

);
}
},
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
childCount: companyInfos.length,
(context, index) {
return CompanyInfoCard(
title: companyInfos[index].title,
contents: companyInfos[index].contents,
subTitle: companyInfos[index].subTitle,
subContents: companyInfos[index].subContents,
onTap: companyInfos[index].onTap,
);
},
),
),
],
),
);
}
}
79 changes: 79 additions & 0 deletions lib/features/tutis/views/s_terms_of_use.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import 'dart:js_interop';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:tuti/common/constraints_scaffold.dart';
import 'package:tuti/constants/color.dart';
import 'package:tuti/constants/gaps.dart';
import 'package:tuti/constants/string.dart';
import 'package:tuti/features/tutis/models/company_info.dart';
import 'package:tuti/features/tutis/widgets/tuti_widgets/tuti_header_mobile.dart';
import 'package:tuti/features/tutis/widgets/tuti_widgets/w_company_info_card.dart';

class TermsOfUseScreen extends StatelessWidget {
const TermsOfUseScreen({super.key});

static const String routeName = "termsOfUse";
static const String routePath = "/termsOfUse";

@override
Widget build(BuildContext context) {
final List<String> tabs = <String>['이용약관', '개인정보 처리방침', '환불 정책'];
final CompanyInfo termsOfUse = CompanyInfo(
title: '이용약관',
contents: termsOfUseContents + minorContents + updateOfAccountInfo,
onTap: () {});
final CompanyInfo privacyPolicy = CompanyInfo(
title: '개인정보 처리방침',
contents: privacyPolicyIntroContents +
privacyPolicyTableOfContents +
privacyPolicyPurposeOfProcessingPersonalInfo +
privacyPolicyProcessingRetentionPeriodOfPersonalInfo,
onTap: () {});
final CompanyInfo refundPolicy = CompanyInfo(
title: '환불 정책',
contents: refundPolicyServiceOfSales +
refundPolicyCoachingRights +
refundPolicyInquiry,
onTap: () {});
final List<CompanyInfo> companyInfos = [
termsOfUse,
privacyPolicy,
refundPolicy
];

return DefaultTabController(
length: tabs.length,
child: Scaffold(
body: Column(
children: [
const TuTiHeaderMobile(),
TabBar(
indicatorColor: ColorConstants.primaryColor,
labelColor: ColorConstants.primaryColor,
dividerColor: ColorConstants.primaryColor,
tabs: tabs.map((String name) => Text(name)).toList(),
),
Flexible(
flex: 11,
child: TabBarView(
children: companyInfos
.map((CompanyInfo info) => CompanyInfoCard(
title: info.title,
contents: info.contents,
onTap: info.onTap,
))
.toList(),
),
),
Flexible(
flex: 1,
child: Container(),
),
],
),
),
);
}
}
6 changes: 4 additions & 2 deletions lib/features/tutis/widgets/tuti_widgets/main_banner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@ class TuTiBanner extends ConsumerWidget {
{super.key,
required this.onTap,
required this.title,
required this.subtitle});
required this.subtitle,
this.margin});
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

객체 생성 시 constraintScaffold에서 제약 조건을 부과하고 있어 임의로 해당 배너의 크기를 조절하지 못하여 margin을 받아 custom하게 크기를 조절해주기 위해 margin을 받도록 했습니다.


final VoidCallback onTap;
final String title;
final String subtitle;
final EdgeInsets? margin;

@override
Widget build(BuildContext context, WidgetRef ref) {
return GestureDetector(
onTap: onTap,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 10.w),
margin: margin ?? EdgeInsets.symmetric(horizontal: 10.w),
padding: EdgeInsets.symmetric(horizontal: 13.w, vertical: 10.h),
height: 80.h,
decoration: ShapeDecoration(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:tuti/common/service/navigation_index_provder.dart';
import 'package:tuti/common/service/token_provider.dart';
import 'package:tuti/common/tuti_icon.dart';
import 'package:tuti/features/profile/models/member_model.dart';
import 'package:tuti/features/tutis/views/personal_branding_screen.dart';
import 'package:tuti/features/tutis/views/s_personal_branding.dart';
import 'package:tuti/features/tutis/widgets/tuti_button_widget.dart';
import 'package:tuti/features/tutis/widgets/tuti_widgets/main_banner.dart';
import 'package:tuti/features/tutis/widgets/tuti_widgets/tuti_login_dialog.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ import '../../../../common/tuti_text.dart';
import '../../../../constants/gaps.dart';

class TuTiHeaderMobile extends ConsumerStatefulWidget {
const TuTiHeaderMobile({
super.key,
});
const TuTiHeaderMobile({super.key});

@override
ConsumerState<TuTiHeaderMobile> createState() => _TuTiHeaderMobileState();
Expand Down
Loading