Skip to content

Commit

Permalink
Merge pull request #52 from 2024-Saphy/feat/SAPHY-32-search-page
Browse files Browse the repository at this point in the history
[FEAT] : Complete Purchase Process
  • Loading branch information
cho4u4o authored Oct 15, 2024
2 parents a868ecf + 39e337b commit 26758b9
Show file tree
Hide file tree
Showing 10 changed files with 386 additions and 120 deletions.
51 changes: 25 additions & 26 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,30 @@ class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return const ScreenController();
// return MaterialApp(
// title: 'Saphy',
// theme: ThemeData(
// colorScheme: ColorScheme.fromSeed(seedColor: altBlack),
// useMaterial3: true,
// ),
// debugShowCheckedModeBanner: false,
// initialRoute: WelcomeScreen.id,
// routes: {
// WelcomeScreen.id: (context) => const WelcomeScreen(),
// SignupScreen.id: (context) => const SignupScreen(
// socialType: '',
// userEmail: '',
// userName: '',
// userPhotoUrl: '',
// ),
// OtpScreen.id: (context) => OtpScreen(
// verificationId: '',
// phoneNumber: '',
// onVerificationSuccess: () {},
// ),
// SplashSellingScreen.id: (context) => const SplashSellingScreen(),
// ScreenController.id: (context) => const ScreenController(),
// },
// );
return MaterialApp(
title: 'Saphy',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: altBlack),
useMaterial3: true,
),
debugShowCheckedModeBanner: false,
initialRoute: WelcomeScreen.id,
routes: {
WelcomeScreen.id: (context) => const WelcomeScreen(),
SignupScreen.id: (context) => const SignupScreen(
socialType: '',
userEmail: '',
userName: '',
userPhotoUrl: '',
),
OtpScreen.id: (context) => OtpScreen(
verificationId: '',
phoneNumber: '',
onVerificationSuccess: () {},
),
SplashSellingScreen.id: (context) => const SplashSellingScreen(),
ScreenController.id: (context) => const ScreenController(),
},
);
}
}
35 changes: 20 additions & 15 deletions lib/models/product.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Product {
String color;
String storage;
String grade;
ImageModel descriptionImage;

Product({
required this.id,
Expand All @@ -23,24 +24,27 @@ class Product {
required this.color,
required this.storage,
required this.grade,
required this.descriptionImage,
});

factory Product.fromJson(Map<String, dynamic> json) {
return Product(
id: json['id'],
deviceType: json['deviceType'] ?? "",
name: json['name'] ?? "",
description: json['description'] ?? "",
price: json['price'],
stock: json['stock'] ?? "",
images: (json['images'] as List)
.map((item) => ImageModel.fromJson(item))
.toList(),
brand: json['brand'] ?? "",
color: json['color'] ?? "",
storage: json['storage'] ?? "",
grade: json['grade'] ?? "",
);
id: json['id'],
deviceType: json['deviceType'] ?? "",
name: json['name'] ?? "",
description: json['description'] ?? "",
price: json['price'],
stock: json['stock'] ?? "",
images: (json['images'] as List)
.map((item) => ImageModel.fromJson(item))
.toList(),
brand: json['brand'] ?? "",
color: json['color'] ?? "",
storage: json['storage'] ?? "",
grade: json['grade'] ?? "",
descriptionImage: json['descriptionImage'] != null
? ImageModel.fromJson(json['descriptionImage'])
: ImageModel(name: "", url: ""));
}

Map<String, dynamic> toJson() {
Expand All @@ -51,11 +55,12 @@ class Product {
'description': description,
'price': price,
'stock': stock,
'images': images, // 직접 저장
'images': images,
'brand': brand,
'color': color,
'storage': storage,
'grade': grade,
"descriptionImage": images,
};
}
}
Expand Down
3 changes: 1 addition & 2 deletions lib/screens/main/main_screen.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:saphy/models/product.dart';
Expand Down Expand Up @@ -146,7 +145,7 @@ class _MainScreenState extends State<MainScreen> {
} else if (!snapshot.hasData ||
snapshot.data!.isEmpty) {
return const Center(
child: Text('No products found')); // 데이터 없음 메시지
child: Text('상품이 없습니다')); // 데이터 없음 메시지
} else {
final products = snapshot.data!; // 데이터 가져오기
return Wrap(
Expand Down
79 changes: 76 additions & 3 deletions lib/screens/products/liked_list_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import 'package:flutter/widgets.dart';
// import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:intl/intl.dart';
import 'package:saphy/models/product.dart';
import 'package:saphy/service/authentication/secure_storage.dart';
import 'package:saphy/utils/textstyles.dart';
import 'package:saphy/widgets/product_card.dart';
import 'package:saphy/utils/colors.dart';
import 'package:saphy/widgets/app_bar.dart';
import 'package:dio/dio.dart';

class LikedListPage extends StatefulWidget {
const LikedListPage({super.key});
Expand All @@ -17,6 +19,53 @@ class LikedListPage extends StatefulWidget {

class _LikedListPageState extends State<LikedListPage> {
final NumberFormat numberFormat = NumberFormat('###,###,###,###');
late Future<List<Product>> _products;
int cnt = 0;

Future<List<Product>> getProducts() async {
final dio = Dio();
String? accessToken = await readAccessToken();

try {
final response = await dio.get(
'https://saphy.site/item-wishes/',
options: Options(
headers: {
'Authorization': 'Bearer $accessToken', // 필요한 헤더 추가
},
),
);
if (response.statusCode == 200) {
final data = response.data as Map<String, dynamic>;
if (data['results'] != null) {
List<Product> products = (data['results'] as List)
.map((item) => Product.fromJson(item))
.toList();
return products;
} else {
throw Exception('No results found in the response');
}
} else {
throw Exception('Failed to load products');
}
} catch (e) {
return [];
}
}

@override
void initState() {
super.initState();
_products = getProducts();
countProducts();
}

Future<void> countProducts() async {
List<Product> products = await getProducts();
setState(() {
cnt = products.length;
});
}

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -53,15 +102,39 @@ class _LikedListPageState extends State<LikedListPage> {
),
),
),
const SliverPadding(
padding: EdgeInsets.all(20),
SliverPadding(
padding: const EdgeInsets.all(20),
sliver: SliverToBoxAdapter(
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.spaceBetween,
spacing: 15,
runSpacing: 15,
children: [],
children: [
FutureBuilder(
future: _products,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error.toString()}');
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const Center(child: Text('상품이 없습니다'));
} else {
final products = snapshot.data!;
return Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.spaceBetween,
spacing: 15,
runSpacing: 15,
children: products
.map((product) => ProductCard(product: product))
.toList(),
);
}
},
)
],
),
),
),
Expand Down
62 changes: 60 additions & 2 deletions lib/screens/products/product_detail_page.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:saphy/screens/purchase/purchase_page.dart';
import 'package:saphy/service/authentication/secure_storage.dart';
import 'package:saphy/utils/colors.dart';
import 'package:saphy/utils/number_format.dart';
import 'package:saphy/utils/textstyles.dart';
Expand All @@ -17,6 +18,7 @@ class ProductDetail extends StatefulWidget {

class _ProductDetailState extends State<ProductDetail> {
Product? productDetail;
bool isWished = false; // 아이템이 찜되었는지 상태를 관리

@override
void initState() {
Expand Down Expand Up @@ -62,10 +64,58 @@ class _ProductDetailState extends State<ProductDetail> {
color: "color",
storage: "storage",
grade: "grade",
descriptionImage: ImageModel(name: "name", url: "url"),
);
}
}

Future<void> toggleWish() async {
final dio = Dio();
try {
String token = await readJwt();
token = token.toString().split(" ")[2];

if (!isWished) {
// 아이템을 찜하는 POST 요청
final response = await dio.post(
'https://saphy.site/item-wishes?itemId=${widget.product.id}',
options: Options(
headers: {
'Authorization': token,
},
),
);

if (response.statusCode == 201) {
// 요청이 성공적으로 처리된 경우
setState(() {
isWished = true; // 아이템이 찜 상태로 변경
});
}
} else {
// 아이템 찜 해제하는 POST 요청
final response = await dio.delete(
'https://saphy.site/item-wishes/${widget.product.id}', // 삭제 요청을 보낼 URL
options: Options(
headers: {
'Authorization': 'Bearer $token',
},
),
);

if (response.statusCode == 200) {
// 요청이 성공적으로 처리된 경우
setState(() {
isWished = false; // 아이템이 찜 해제 상태로 변경
});
}
}
} catch (e) {
print('Error: $e');
// 에러 처리 로직 추가 가능
}
}

@override
Widget build(BuildContext context) {
var screenWidth = MediaQuery.of(context).size.width;
Expand Down Expand Up @@ -350,8 +400,16 @@ class _ProductDetailState extends State<ProductDetail> {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.favorite_outline)),
onPressed: toggleWish,
icon: Icon(
isWished
? Icons.favorite
: Icons.favorite_outline, // 찜 상태에 따라 아이콘 변경
color: isWished
? Colors.red
: Colors.black, // 찜 상태에 따라 색상 변경
),
),
const SizedBox(width: 10),
Flexible(flex: 1, child: button("구매하기")),
const SizedBox(width: 10),
Expand Down
Loading

0 comments on commit 26758b9

Please sign in to comment.