From d2e591e94c4ad654fdb01ed3d5ca0faa8e0ad1cc Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Sun, 3 Sep 2023 00:49:17 +0900 Subject: [PATCH 01/10] =?UTF-8?q?=EC=83=81=ED=92=88=ED=8C=90=EB=A7=A4?= =?UTF-8?q?=EA=B8=80=EA=B4=80=EB=A0=A8=20api=EC=9A=94=EC=B2=AD=EC=BD=94?= =?UTF-8?q?=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/apis/apis.dart | 427 ++++++++++++++++++++++++++------ lib/models/market_articles.dart | 105 +++++--- 2 files changed, 428 insertions(+), 104 deletions(-) diff --git a/lib/apis/apis.dart b/lib/apis/apis.dart index 667e309f..9c8ea2ae 100644 --- a/lib/apis/apis.dart +++ b/lib/apis/apis.dart @@ -20,6 +20,7 @@ import 'dart:convert'; import '../models/board_model.dart'; import '../models/comment_model.dart'; +import '../models/market_articles.dart'; import '../models/memberDetails_model.dart'; import '../models/message_model.dart'; import '../models/partner_model.dart'; @@ -1390,58 +1391,6 @@ class APIs { - /*장터*/ -/* static Future postDataWithImages({ - required String title, - required String status, - required int price, - required String productStatus, - required List images, - required String content, - }) async { - var request = http.MultipartRequest('POST', Uri.parse(apiUrl)); - request.fields['title'] = title; - request.fields['status'] = status; - request.fields['price'] = price.toString(); - request.fields['productStatus'] = productStatus; - request.fields['content'] = content; - - List files = await convertAssetsToFiles(images); - - for (var i = 0; i < files.length; i++) { - var file = files[i]; - var stream = http.ByteStream(Stream.castFrom(file.openRead())); - var length = await file.length(); - - var multipartFile = http.MultipartFile('image$i', stream, length, - filename: 'image$i.jpg'); - - request.files.add(multipartFile); - } - - var response = await request.send(); - if (response.statusCode == 200) { - print('API Response: ${await response.stream.bytesToString()}'); - } else { - print('API Request failed with status ${response.statusCode}'); - } - } - - static Future> convertAssetsToFiles(List assets) async { - List files = []; - - for (var asset in assets) { - final byteData = await asset.getByteData(); - final buffer = byteData.buffer.asUint8List(); - final tempFile = File('${(await getTemporaryDirectory()).path}/${asset.name}'); - await tempFile.writeAsBytes(buffer); - files.add(tempFile); - } - - return files; - }*/ - - /*전체게시판 글 전부 조회*/ static Future> TotalArticles() async { final _url = 'http://3.34.2.246:8080/api/v2/articles'; @@ -1548,7 +1497,6 @@ class APIs { - /* 특정 게시판 게시물 조회 @@ -1601,40 +1549,62 @@ class APIs { */ static Future postArticles(Board board) async { - const url = 'https://aaa1f771-6012-440a-9939-4328d9519a52.mock.pstmn.io/api/v2/community-articles'; + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; - var request = http.MultipartRequest('POST', Uri.parse(url)); + const url = 'https://aaa1f771-6012-440a-9939-4328d9519a52.mock.pstmn.io/api/v2/community-articles'; - // FormData 텍스트 필드 추가 - request.fields['title'] = board.title!; - request.fields['content'] = board.content!; - request.fields['category'] = board.category!; + var request = http.MultipartRequest('POST', Uri.parse(url)); + // FormData 텍스트 필드 추가 + request.fields['title'] = board.title!; + request.fields['content'] = board.content!; + request.fields['category'] = board.category!; - // FormData 파일 필드 추가 - if (board.images != null && board.images!.isNotEmpty) { - for (String imagePath in board.images!) { - if (imagePath.isNotEmpty) { - var file = await http.MultipartFile.fromPath('imageUrls', imagePath); - request.files.add(file); + // FormData 파일 필드 추가 + if (board.images != null && board.images!.isNotEmpty) { + for (String imagePath in board.images!) { + if (imagePath.isNotEmpty) { + var file = await http.MultipartFile.fromPath('imageUrls', imagePath); + request.files.add(file); + } } } - } - // request 전송 - var response = await request.send(); + // Authorization 헤더 설정 + request.headers['Authorization'] = 'Bearer $accessToken'; - // success - if (response.statusCode == 200) { - print(await response.stream.bytesToString()); - return true; - // fail - } else { - print(await response.stream.bytesToString()); - return false; + // request 전송 + var response = await request.send(); + + // success + if (response.statusCode == 200) { + print(await response.stream.bytesToString()); + return true; + } else { + final responseBody = await response.stream.bytesToString(); + final errorCode = json.decode(responseBody)['code']; + + if (errorCode == 'AT-C-002') { + print('액세스 토큰 만료'); + throw 'AT-C-002'; + } else if (errorCode == 'AT-C-007') { + print('로그아웃된 토큰'); + throw 'AT-C-007'; + } else { + print('API request failed: ${response.statusCode}'); + print('오류 메시지: ${json.decode(responseBody)['message']}'); + throw Exception('게시글 업로드 오류'); + } + } + } catch (error) { + print('Error posting article: $error'); + throw Exception('게시글 업로드 오류'); } } + /* 게시물 삭제 @@ -1909,6 +1879,311 @@ class APIs { } } + + /*상품판매글 모두 조회*/ + static Future> getMarketArticles() async { + var _url = 'https://3.34.2.246:8080/api/v2/market-articles'; + + // 토큰 읽어오기 + var jwtToken = await storage.read(key: 'token'); + + // accessToken만 보내기 + jwtToken = json.decode(jwtToken!)['data']['accessToken']; + + var response = await http.get( + Uri.parse(_url), + headers: { + 'Authorization': 'Bearer $jwtToken', + 'Content-Type': 'application/json' + }, + ); + + if (response.statusCode == 200) { + List body = json.decode(utf8.decode(response.bodyBytes))['data']; + return body.map((dynamic item) => MarketBoard.fromJson(item)).toList(); + } else { + print(json.decode(utf8.decode(response.bodyBytes))); + if (json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-002') { + print('액세스 토큰 만료'); + throw 'AT-C-002'; + } else if (json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-007') { + print('로그아웃된 토큰'); + throw 'AT-C-007'; + } else { + throw Exception('요청 오류'); + } + } + } + + /*상품 판매글 검색*/ + static Future> marketSearch(String keyword) async { + try { + var jwtToken = await storage.read(key: 'token'); + jwtToken = json.decode(jwtToken!)['data']['accessToken']; + + final response = await http.get( + Uri.parse('http://3.34.2.246:8080/api/v2/market-articles?search-keyword=$keyword'), + headers: { + 'Authorization': 'Bearer $jwtToken', + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final data = json.decode(utf8.decode(response.bodyBytes)); + final List articlesData = data['data']; + + // 데이터를 List 객체로 반환 + List articles = articlesData.map((articleData) { + return MarketBoard.fromJson(articleData); + }).toList(); + + return articles; + } else { + print(json.decode(utf8.decode(response.bodyBytes))); + if (json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-002') { + print('액세스 토큰 만료'); + throw 'AT-C-002'; + } else if (json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-007') { + print('로그아웃된 토큰'); + throw 'AT-C-007'; + } else { + throw Exception('요청 오류'); + } + } + } catch (error) { + print('Error fetching market search results: $error'); + return []; // Empty list on error + } + } + + + /*상품 판매글 생성*/ + static Future createMarketArticle(MarketBoard marketArticle) async { + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; + + var request = http.MultipartRequest( + 'POST', + Uri.parse('http://3.34.2.246:8080/api/v2/market-articles'), + ); + + // 텍스트 필드 추가 + request.fields['title'] = marketArticle.title!; + request.fields['content'] = marketArticle.content!; + request.fields['price'] = marketArticle.price.toString(); + request.fields['productStatus'] = marketArticle.productStatus!; + + // 이미지 파일 필드 추가 + if (marketArticle.images != null && marketArticle.images!.isNotEmpty) { + for (String imagePath in marketArticle.images!) { + if (imagePath.isNotEmpty) { + var file = await http.MultipartFile.fromPath('imageUrls', imagePath); + request.files.add(file); + } + } + } + + // Authorization 헤더 설정 + request.headers['Authorization'] = 'Bearer $accessToken'; + + // request 전송 + var response = await request.send(); + + // 성공 + if (response.statusCode == 201) { + print('상품 판매글 생성'); + return true; + } else { + final responseBody = await response.stream.bytesToString(); + final errorCode = json.decode(responseBody)['code']; + + if (errorCode == 'AT-C-002') { + print('액세스 토큰 만료'); + throw 'AT-C-002'; + } else if (errorCode == 'AT-C-007') { + print('로그아웃된 토큰'); + throw 'AT-C-007'; + } else { + print('API request failed: ${response.statusCode}'); + print('오류 메시지: ${json.decode(responseBody)['message']}'); + throw Exception('상품 판매글 생성 오류'); + } + } + } catch (error) { + print('Error creating market article: $error'); + throw Exception('상품 판매글 생성 오류'); + } + } + + /*특정 판매글 수정*/ + static Future updateMarketArticle(int articleId, Map updateData) async { + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; + + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$articleId'); + + final response = await http.patch( + url, + headers: { + 'Authorization': 'Bearer $accessToken', + 'Content-Type': 'application/json', + }, + body: json.encode(updateData), + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final message = responseBody['message']; + return message; + } else { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final errorCode = responseBody['code']; + + if (errorCode == 'AT-C-002') { + throw '액세스 토큰 만료'; + } else if (errorCode == 'AT-C-007') { + throw '로그아웃된 토큰'; + } else { + throw Exception('상품 판매글 수정 오류'); + } + } + } catch (error) { + print('Error updating market article: $error'); + throw Exception('상품 판매글 수정 오류'); + } + } + + /* 특정 판매글 삭제*/ + static Future deleteMarketArticle(int articleId) async { + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; + + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$articleId'); + + final response = await http.delete( + url, + headers: { + 'Authorization': 'Bearer $accessToken', + }, + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final message = responseBody['message']; + return message; + } else { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final errorCode = responseBody['code']; + + if (errorCode == 'AT-C-002') { + throw '액세스 토큰 만료'; + } else if (errorCode == 'AT-C-007') { + throw '로그아웃된 토큰'; + } else { + throw Exception('상품 판매글 삭제 오류'); + } + } + } catch (error) { + print('Error deleting market article: $error'); + throw Exception('상품 판매글 삭제 오류'); + } + } + + + /* 특정 판매글 찜 등록*/ + static Future addMarketArticleBookmark(int articleId) async { + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; + + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$articleId/bookmarks'); + + final response = await http.post( + url, + headers: { + 'Authorization': 'Bearer $accessToken', + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final message = responseBody['message']; + return message; + } else { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final errorCode = responseBody['code']; + + if (errorCode == 'AT-C-002') { + throw '액세스 토큰 만료'; + } else if (errorCode == 'AT-C-007') { + throw '로그아웃된 토큰'; + } else { + throw Exception('북마크 등록 오류'); + } + } + } catch (error) { + print('Error adding market article bookmark: $error'); + throw Exception('북마크 등록 오류'); + } + } + + + /*특정 판매글 찜 제거*/ + static Future removeMarketArticleBookmark(int articleId) async { + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; + + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$articleId/bookmarks'); + + final response = await http.delete( + url, + headers: { + 'Authorization': 'Bearer $accessToken', + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final message = responseBody['message']; + return message; + } else { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final errorCode = responseBody['code']; + + if (errorCode == 'AT-C-002') { + throw '액세스 토큰 만료'; + } else if (errorCode == 'AT-C-007') { + throw '로그아웃된 토큰'; + } else { + throw Exception('북마크 해제 오류'); + } + } + } catch (error) { + print('Error removing market article bookmark: $error'); + throw Exception('북마크 해제 오류'); + } + } + + + /*상품 판매글 부모 댓글 등록*/ + + + + /*특정 판매글 댓글 삭제*/ + + + /*상품 판매글 댓글 전체 조회*/ + + + /*특정 상품 판매글 댓글에 대댓글 등록*/ + } diff --git a/lib/models/market_articles.dart b/lib/models/market_articles.dart index e449a5f3..773bd08d 100644 --- a/lib/models/market_articles.dart +++ b/lib/models/market_articles.dart @@ -1,44 +1,93 @@ -class MarketArticle { - int? marketArticleId; +class MarketBoard { + int? articleId; String? title; String? status; int? price; - int? likeCount; - int? commentCount; - String? thumbnailImageUrl; + String? productStatus; + String? content; + int? marketArticleBookmarkCount; + int? commentsCount; + List? images; + Member? member; String? createdAt; - MarketArticle({ - this.marketArticleId, + MarketBoard({ + this.articleId, this.title, this.status, this.price, - this.likeCount, - this.commentCount, - this.thumbnailImageUrl, + this.productStatus, + this.content, + this.marketArticleBookmarkCount, + this.commentsCount, + this.images, + this.member, this.createdAt, }); - factory MarketArticle.fromJson(Map json) => MarketArticle( - marketArticleId: json['marketArticleId'], - title: json['title'], - status: json['status'], - price: json['price'], - likeCount: json['likeCount'], - commentCount: json['commentCount'], - thumbnailImageUrl: json['thumbnailImageUrl'], - createdAt: json['createdAt'], - ); + MarketBoard.fromJson(Map json) { + articleId = json['articleId']; + title = json['title']; + status = json['status']; + price = json['price']; + productStatus = json['productStatus']; + content = json['content']; + marketArticleBookmarkCount = json['marketArticleBookmarkCount']; + commentsCount = json['commentsCount']; + images = json['images'].cast(); + member = json['member'] != null ? Member.fromJson(json['member']) : null; + createdAt = json['createdAt']; + } + + Map toJson() { + final Map data = {}; + data['articleId'] = articleId; + data['title'] = title; + data['status'] = status; + data['price'] = price; + data['productStatus'] = productStatus; + data['content'] = content; + data['marketArticleBookmarkCount'] = marketArticleBookmarkCount; + data['commentsCount'] = commentsCount; + data['images'] = images; + if (member != null) { + data['member'] = member!.toJson(); + } + data['createdAt'] = createdAt; + return data; + } +} + +class Member { + int? memberId; + String? email; + String? name; + String? nationality; + String? profileImageUrl; + + Member({ + this.memberId, + this.email, + this.name, + this.nationality, + this.profileImageUrl, + }); + + Member.fromJson(Map json) { + memberId = json['memberId']; + email = json['email']; + name = json['name']; + nationality = json['nationality']; + profileImageUrl = json['profileImageUrl']; + } Map toJson() { - final Map data = {}; - data['title'] = this.title; - data['status'] = this.status; - data['price'] = this.price; - data['likeCount'] = this.likeCount; - data['commentCount'] = this.commentCount; - data['thumbnailImageUrl'] = this.thumbnailImageUrl; - data['createdAt'] = this.createdAt; + final Map data = {}; + data['memberId'] = memberId; + data['email'] = email; + data['name'] = name; + data['nationality'] = nationality; + data['profileImageUrl'] = profileImageUrl; return data; } } From e2dd68b7acbb8700ade0350f4cb8ad3fc9f5ef29 Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Sun, 3 Sep 2023 01:06:09 +0900 Subject: [PATCH 02/10] =?UTF-8?q?=EB=8C=93=EA=B8=80=EA=B4=80=EB=A0=A8=20ap?= =?UTF-8?q?i=20=EC=9A=94=EC=B2=AD=20=EC=BD=94=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/apis/apis.dart | 160 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 156 insertions(+), 4 deletions(-) diff --git a/lib/apis/apis.dart b/lib/apis/apis.dart index 9c8ea2ae..0133a39e 100644 --- a/lib/apis/apis.dart +++ b/lib/apis/apis.dart @@ -2172,17 +2172,169 @@ class APIs { } + /*상품 판매글 댓글 전체 조회*/ + static Future> getMarketArticleComments(int marketArticleId) async { + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; + + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$marketArticleId/market-article-comments'); + + final response = await http.get( + url, + headers: { + 'Authorization': 'Bearer $accessToken', + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final commentsData = responseBody['data']; + + // 댓글 데이터를 파싱하여 Comment 객체로 변환 + final comments = commentsData.map((commentJson) { + return Comment.fromJson(commentJson); + }).toList(); + + return comments; + } else { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final errorCode = responseBody['code']; + + if (errorCode == 'AT-C-002') { + throw '액세스 토큰 만료'; + } else if (errorCode == 'AT-C-007') { + throw '로그아웃된 토큰'; + } else { + throw Exception('댓글 조회 오류'); + } + } + } catch (error) { + print('Error fetching market article comments: $error'); + throw Exception('댓글 조회 오류'); + } + } + + /*상품 판매글 부모 댓글 등록*/ - + static Future createMarketArticleComment(int marketArticleId, String content) async { + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; + + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$marketArticleId/market-article-comments'); + + final response = await http.post( + url, + headers: { + 'Authorization': 'Bearer $accessToken', + 'Content-Type': 'application/json', + }, + body: json.encode({'content': content}), + ); + + if (response.statusCode == 201) { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final message = responseBody['message']; + return message; + } else { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final errorCode = responseBody['code']; + + if (errorCode == 'AT-C-002') { + throw '액세스 토큰 만료'; + } else if (errorCode == 'AT-C-007') { + throw '로그아웃된 토큰'; + } else { + throw Exception('댓글 생성 오류'); + } + } + } catch (error) { + print('Error creating market article comment: $error'); + throw Exception('댓글 생성 오류'); + } + } + + + /*특정 판매글 댓글 삭제*/ + static Future deleteMarketArticleComment(int marketArticleCommentId) async { + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; + + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-article-comments/$marketArticleCommentId'); + final response = await http.delete( + url, + headers: { + 'Authorization': 'Bearer $accessToken', + 'Content-Type': 'application/json', + }, + ); - /*특정 판매글 댓글 삭제*/ + if (response.statusCode == 200) { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final message = responseBody['message']; + return message; + } else { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final errorCode = responseBody['code']; + if (errorCode == 'AT-C-002') { + throw '액세스 토큰 만료'; + } else if (errorCode == 'AT-C-007') { + throw '로그아웃된 토큰'; + } else { + throw Exception('댓글 삭제 오류'); + } + } + } catch (error) { + print('Error deleting market article comment: $error'); + throw Exception('댓글 삭제 오류'); + } + } - /*상품 판매글 댓글 전체 조회*/ + /*특정 상품 판매글 댓글에 대댓글 등록*/ + static Future addMarketArticleCommentReply(int marketArticleId, int marketArticleCommentId, String content) async { + try { + var jwtToken = await storage.read(key: 'token'); + final accessToken = json.decode(jwtToken!)['data']['accessToken']; + + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$marketArticleId/market-article-comments/$marketArticleCommentId'); + + final response = await http.post( + url, + headers: { + 'Authorization': 'Bearer $accessToken', + 'Content-Type': 'application/json', + }, + body: json.encode({'content': content}), + ); + + if (response.statusCode == 200) { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final message = responseBody['message']; + return message; + } else { + final responseBody = json.decode(utf8.decode(response.bodyBytes)); + final errorCode = responseBody['code']; + + if (errorCode == 'AT-C-002') { + throw '액세스 토큰 만료'; + } else if (errorCode == 'AT-C-007') { + throw '로그아웃된 토큰'; + } else { + throw Exception('대댓글 생성 오류'); + } + } + } catch (error) { + print('Error adding market article comment reply: $error'); + throw Exception('대댓글 생성 오류'); + } + } - /*특정 상품 판매글 댓글에 대댓글 등록*/ } From 7635545a464f24b45d474e283f42870424fe6687 Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Sun, 3 Sep 2023 20:28:59 +0900 Subject: [PATCH 03/10] =?UTF-8?q?=EC=83=81=ED=92=88=ED=8C=90=EB=A7=A4?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=EC=A1=B0=ED=9A=8Capi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/translations/en-US.json | 1 + assets/translations/ko-KR.json | 1 + lib/apis/apis.dart | 44 +- lib/models/market_articles.dart | 8 +- lib/views/components/board_drawer_widget.dart | 13 +- lib/views/pages/board/market_board_page.dart | 548 ++++++++++-------- lib/views/pages/board/market_detail_page.dart | 81 +-- .../board/market_posting_board_page.dart | 4 +- 8 files changed, 344 insertions(+), 356 deletions(-) diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index 80928ddb..d2a61ffe 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -265,6 +265,7 @@ "market-posting-content": "• Product name\n• Detailed information (wear and tear, defects, etc.)\n• Mobile phone number or KakaoTalk ID\n* To establish trust for a successful transaction,\n please provide detailed information and various angles of product photos.", "market-posting-content1": "Please enter contents.", "market-posting-title-error": "Up to 30 characters are allowed.", + "market-productStatus": "product Status", "board": "Board", diff --git a/assets/translations/ko-KR.json b/assets/translations/ko-KR.json index ba098d52..478263ff 100644 --- a/assets/translations/ko-KR.json +++ b/assets/translations/ko-KR.json @@ -268,6 +268,7 @@ "market-posting-content1": "내용을 입력해주세요.", "market-posting-title-error": "최대 30자까지 입력가능합니다.", "market_noti": "장터게시판 이용 시 주의사항", + "market-productStatus" : "상품 상태", "modify": "수정하기", diff --git a/lib/apis/apis.dart b/lib/apis/apis.dart index 0133a39e..b47412b5 100644 --- a/lib/apis/apis.dart +++ b/lib/apis/apis.dart @@ -1882,7 +1882,7 @@ class APIs { /*상품판매글 모두 조회*/ static Future> getMarketArticles() async { - var _url = 'https://3.34.2.246:8080/api/v2/market-articles'; + var _url = 'http://3.34.2.246:8080/api/v2/market-articles'; // 토큰 읽어오기 var jwtToken = await storage.read(key: 'token'); @@ -1976,8 +1976,8 @@ class APIs { request.fields['productStatus'] = marketArticle.productStatus!; // 이미지 파일 필드 추가 - if (marketArticle.images != null && marketArticle.images!.isNotEmpty) { - for (String imagePath in marketArticle.images!) { + if (marketArticle.imageUrls != null && marketArticle.imageUrls!.isNotEmpty) { + for (String imagePath in marketArticle.imageUrls!) { if (imagePath.isNotEmpty) { var file = await http.MultipartFile.fromPath('imageUrls', imagePath); request.files.add(file); @@ -2133,44 +2133,6 @@ class APIs { } - /*특정 판매글 찜 제거*/ - static Future removeMarketArticleBookmark(int articleId) async { - try { - var jwtToken = await storage.read(key: 'token'); - final accessToken = json.decode(jwtToken!)['data']['accessToken']; - - final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$articleId/bookmarks'); - - final response = await http.delete( - url, - headers: { - 'Authorization': 'Bearer $accessToken', - 'Content-Type': 'application/json', - }, - ); - - if (response.statusCode == 200) { - final responseBody = json.decode(utf8.decode(response.bodyBytes)); - final message = responseBody['message']; - return message; - } else { - final responseBody = json.decode(utf8.decode(response.bodyBytes)); - final errorCode = responseBody['code']; - - if (errorCode == 'AT-C-002') { - throw '액세스 토큰 만료'; - } else if (errorCode == 'AT-C-007') { - throw '로그아웃된 토큰'; - } else { - throw Exception('북마크 해제 오류'); - } - } - } catch (error) { - print('Error removing market article bookmark: $error'); - throw Exception('북마크 해제 오류'); - } - } - /*상품 판매글 댓글 전체 조회*/ static Future> getMarketArticleComments(int marketArticleId) async { diff --git a/lib/models/market_articles.dart b/lib/models/market_articles.dart index 773bd08d..623dc023 100644 --- a/lib/models/market_articles.dart +++ b/lib/models/market_articles.dart @@ -7,7 +7,7 @@ class MarketBoard { String? content; int? marketArticleBookmarkCount; int? commentsCount; - List? images; + List? imageUrls; Member? member; String? createdAt; @@ -20,7 +20,7 @@ class MarketBoard { this.content, this.marketArticleBookmarkCount, this.commentsCount, - this.images, + this.imageUrls, this.member, this.createdAt, }); @@ -34,7 +34,7 @@ class MarketBoard { content = json['content']; marketArticleBookmarkCount = json['marketArticleBookmarkCount']; commentsCount = json['commentsCount']; - images = json['images'].cast(); + imageUrls = json['imageUrls'].cast(); member = json['member'] != null ? Member.fromJson(json['member']) : null; createdAt = json['createdAt']; } @@ -49,7 +49,7 @@ class MarketBoard { data['content'] = content; data['marketArticleBookmarkCount'] = marketArticleBookmarkCount; data['commentsCount'] = commentsCount; - data['images'] = images; + data['imageUrls'] = imageUrls; if (member != null) { data['member'] = member!.toJson(); } diff --git a/lib/views/components/board_drawer_widget.dart b/lib/views/components/board_drawer_widget.dart index c6ced437..f426faf4 100644 --- a/lib/views/components/board_drawer_widget.dart +++ b/lib/views/components/board_drawer_widget.dart @@ -24,13 +24,16 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/svg.dart'; import '../../apis/apis.dart'; +import '../../models/market_articles.dart'; import '../../repository/sql_message_repository.dart'; import '../pages/board/market_posting_board_page.dart'; class BoardDrawerWidget extends StatefulWidget { - const BoardDrawerWidget({super.key, required this.screenArguments, required this.isTotalBoard, required this.onpressd}); + const BoardDrawerWidget({super.key, required this.screenArguments, required this.isTotalBoard, required this.onpressd, this.marketBoard}); final ScreenArguments screenArguments; + final MarketBoard? marketBoard; + final bool isTotalBoard; final VoidCallback onpressd; @@ -42,6 +45,7 @@ class _BoardDrawerWidgetState extends State { + @override Widget build(BuildContext context) { @@ -118,7 +122,7 @@ class _BoardDrawerWidgetState extends State { onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => MarketBoardPostPage(screenArguments: widget.screenArguments)), + MaterialPageRoute(builder: (context) => MarketBoardPostPage(screenArguments: widget.screenArguments,marketBoard:widget.marketBoard )), ); }, child: Container( @@ -394,7 +398,8 @@ class _BoardDrawerWidgetState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => MarketBoardPage(screenArguments: widget.screenArguments)), + builder: (context) => MarketBoardPage(screenArguments: widget.screenArguments, marketBoard: widget.marketBoard,)), + ); } else{ @@ -402,7 +407,7 @@ class _BoardDrawerWidgetState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => MarketBoardPage(screenArguments: widget.screenArguments)), + builder: (context) => MarketBoardPage(screenArguments: widget.screenArguments, marketBoard: widget.marketBoard,)), ); } }, diff --git a/lib/views/pages/board/market_board_page.dart b/lib/views/pages/board/market_board_page.dart index fa3d4c8e..2a259df7 100644 --- a/lib/views/pages/board/market_board_page.dart +++ b/lib/views/pages/board/market_board_page.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:aliens/apis/apis.dart'; import 'package:aliens/models/chatRoom_model.dart'; import 'package:aliens/models/screenArgument.dart'; import 'package:aliens/repository/sql_message_database.dart'; @@ -12,12 +13,14 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import '../../../models/market_articles.dart'; import '../../components/board_drawer_widget.dart'; class MarketBoardPage extends StatefulWidget { - const MarketBoardPage({super.key, required this.screenArguments}); + const MarketBoardPage({super.key, required this.screenArguments, required this.marketBoard}); final ScreenArguments screenArguments; + final MarketBoard? marketBoard; @@ -27,299 +30,334 @@ class MarketBoardPage extends StatefulWidget { class _MarketBoardPageState extends State { bool isDrawerStart = false; + List marketBoardList = []; + + + void initState() { + super.initState(); + _fetchMarketArticles(); + } + + Future _fetchMarketArticles() async { + try { + var fetchedData = await APIs.getMarketArticles(); // API 호출 함수 호출 + setState(() { + marketBoardList = fetchedData; // 불러온 데이터를 리스트에 할당 + }); + } catch (error) { + // 에러 처리 + print("API 호출 중 오류 발생: $error"); + } + } + @override Widget build(BuildContext context) { - final double screenWidth = MediaQuery.of(context).size.height; + final double screenWidth = MediaQuery + .of(context) + .size + .height; final bool isSmallScreen = screenWidth <= 700; return Scaffold( - appBar: AppBar( - backgroundColor:Color(0xff7898ff), - toolbarHeight:56, + appBar: AppBar( + backgroundColor: Color(0xff7898ff), + toolbarHeight: 56, leadingWidth: 100, leading: Row( - children: [ - IconButton( - onPressed: () { - setState(() { - Navigator.of(context).pop(); - }); - }, - icon: SvgPicture.asset( - 'assets/icon/icon_back.svg', - color: Colors.white, - width: 17.r, - height: 17.r, - ) - ), - IconButton( - onPressed: () { - setState(() { - isDrawerStart = !isDrawerStart; - }); - }, - icon: SvgPicture.asset( - 'assets/icon/ICON_list.svg', - width: 20.r, - height: 20.r, + children: [ + IconButton( + onPressed: () { + setState(() { + Navigator.of(context).pop(); + }); + }, + icon: SvgPicture.asset( + 'assets/icon/icon_back.svg', + color: Colors.white, + width: 17.r, + height: 17.r, + ) + ), + IconButton( + onPressed: () { + setState(() { + isDrawerStart = !isDrawerStart; + }); + }, + icon: SvgPicture.asset( + 'assets/icon/ICON_list.svg', + width: 20.r, + height: 20.r, + color: Colors.white, + ), color: Colors.white, + ), + ], + ), + title: Text('market'.tr(), + style: TextStyle( + color: Colors.white, + fontSize: 18.spMin, + ) + ), + centerTitle: true, + actions: [ + Padding(padding: EdgeInsets.all(8), child: SvgPicture.asset( + 'assets/icon/icon_search.svg', + width: 25.r, + height: 25.r, color: Colors.white, - - ), + ),), ], - ), - title: Text('market'.tr(), - style: TextStyle( - color: Colors.white, - fontSize: 18.spMin, - ) - ), - centerTitle: true, - actions: [ - Padding(padding: EdgeInsets.all(8), child: SvgPicture.asset( - 'assets/icon/icon_search.svg', - width: 25.r, - height: 25.r, - color: Colors.white, - ),), - ], - ), - body:isDrawerStart - ? BoardDrawerWidget(screenArguments: widget.screenArguments, isTotalBoard: false, onpressd: () { }, - ) - :Column( - children: [ - InkWell( - onTap: (){ - Navigator.pushNamed(context,'/market/notice'); - }, - child: Container( - margin: EdgeInsets.only(right: 10,left: 10, top: 10, bottom: 10).r, - padding: EdgeInsets.only(right: 10,left: 10).r, - width: double.infinity, - height: 42.spMin, - decoration: BoxDecoration( - color: Color(0xffE7E7E7), - borderRadius: BorderRadius.circular(10), // 모서리를 둥글게 만듦 - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox(child:Container()), - Row( - children: [ - SvgPicture.asset( - 'assets/icon/icon_info.svg', - color: Color(0xff616161), - width: 18.spMin, - height: 18.spMin, - ), - Text( - ' ${'market-noti'.tr()}', - style: TextStyle( - fontSize: 14.spMin, - fontWeight: FontWeight.w600, - color: Color(0xff616161) + ), + body: isDrawerStart + ? BoardDrawerWidget(screenArguments: widget.screenArguments, + isTotalBoard: false, + onpressd: () {}, + ) + : Column( + children: [ + InkWell( + onTap: () { + Navigator.pushNamed(context, '/market/notice'); + }, + child: Container( + margin: EdgeInsets + .only(right: 10, left: 10, top: 10, bottom: 10) + .r, + padding: EdgeInsets + .only(right: 10, left: 10) + .r, + width: double.infinity, + height: 42.spMin, + decoration: BoxDecoration( + color: Color(0xffE7E7E7), + borderRadius: BorderRadius.circular(10), // 모서리를 둥글게 만듦 + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox(child: Container()), + Row( + children: [ + SvgPicture.asset( + 'assets/icon/icon_info.svg', + color: Color(0xff616161), + width: 18.spMin, + height: 18.spMin, ), - ) - ], - ), - Icon( - Icons.arrow_forward_ios, - size: 18.spMin, - color: Color(0xffC1C1C1), - ) - ], + Text( + ' ${'market-noti'.tr()}', + style: TextStyle( + fontSize: 14.spMin, + fontWeight: FontWeight.w600, + color: Color(0xff616161) + ), + ) + ], + ), + Icon( + Icons.arrow_forward_ios, + size: 18.spMin, + color: Color(0xffC1C1C1), + ) + ], + ), ), ), - ), - Expanded( - child:_contentWidget(), - ) - ], - ) + Expanded( + child: _contentWidget(), + ) + ], + ) ); } - Widget _contentWidget(){ + Widget _contentWidget() { + List marketBoardList = []; + return ListView.separated( - itemBuilder:(BuildContext context, int index){ - return InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => MarketDetailPage(screenArguments: widget.screenArguments)), - ); - }, - child: Container( - padding: EdgeInsets.only(right: 20.w,left: 20.w,top:12.h,bottom: 12.h), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - //여기 사진 넣기 - width: 124.spMin, height: 124.spMin, - decoration: BoxDecoration( - color: Color(0xffF8F8F8), - borderRadius: BorderRadius.all(Radius.circular(10)), + itemBuilder: (BuildContext context, int index) { + MarketBoard marketBoard = marketBoardList[index]; + return InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + MarketDetailPage( + screenArguments: widget.screenArguments, + marketBoard: marketBoard, + ), + ), + ); + }, + child: Container( + padding: EdgeInsets.only( + right: 20.w, left: 20.w, top: 12.h, bottom: 12.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + width: 124.spMin, + height: 124.spMin, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10)), + image: DecorationImage( + fit: BoxFit.cover, + image: NetworkImage(marketBoard.imageUrls?.first ?? ""), // 첫 번째 이미지를 가져오기 + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only( + left: 10.w, right: 10.w, top: 2.h, bottom: 2.h), + height: 21.spMin, + child: Text( + marketBoard.productStatus ?? "", // 상품 상태 정보 + style: TextStyle( + fontSize: 10.spMin, color: Colors.white), + textAlign: TextAlign.center, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(50)), + color: Color(0xff7898FF), + ), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, + ], + ), + ), + SizedBox(width: 5.w), + Container( + width: MediaQuery.of(context).size.width - 170.w, + height: 124.spMin, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Center( - child: ClipRRect( - //사진이 있으면 없어질 것들 - borderRadius: BorderRadius.all(Radius.circular(10)), - child: - Image.asset('assets/icon/ICON_photo_1.png', height: 44.spMin), + Text( + '[${marketBoard.status ?? ""}]', // 상태 정보 사용 + style: TextStyle( + color: Color(0xff616161), + fontSize: 16.spMin, + fontWeight: FontWeight.w600, ), ), - Container( - padding: EdgeInsets.only(left:10.w, right: 10.w, top: 2.h, bottom: 2.h), - height: 21.spMin, - child: Text( - '거의 새 것', //productstatus - style: TextStyle(fontSize: 10.spMin, color: Colors.white), - textAlign: TextAlign.center, - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(50)), - color: Color(0xff7898FF) - ), - ), - - ], - ), - ), //물건 사진 - SizedBox(width: 5.w), - Container( - width: MediaQuery.of(context).size.width -170.w , - height: 124.spMin, //높이를 물건사진의 높이와 같게 - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - '[판매중]', //status + marketBoard.createdAt ?? "", // 생성 날짜 정보 사용 style: TextStyle( - color: Color(0xff616161), - fontSize: 16.spMin, - fontWeight: FontWeight.w600 + color: Color(0xffC1C1C1), + fontSize: 12.spMin, ), ), - // Expanded(child: SizedBox()), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text('23.08.06',//createdAt - style: TextStyle( - color: Color(0xffC1C1C1), - fontSize: 12.spMin, - ), - ), - InkWell( - onTap: (){ - showDialog( - context: context, - builder: (BuildContext context) { - return SimpleDialog( - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(20.0), - ), - children: [ - SimpleDialogOption( - child: Text( - '${'modity'.tr()}', - ), - onPressed: () { - - }, - ), - SimpleDialogOption( - child: Text('${'chatting-report1'.tr()}'), - onPressed: () { - }, - ), - ], - ); - }); - + InkWell( + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return SimpleDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 20.0), + ), + children: [ + SimpleDialogOption( + child: Text('${'modify'.tr()}'), + onPressed: () {}, + ), + SimpleDialogOption( + child: Text( + '${'chatting-report1'.tr()}'), + onPressed: () {}, + ), + ], + ); }, - child: SvgPicture.asset( - 'assets/icon/ICON_more.svg', - width: 16.r, - height: 16.r, - ) - ) - ], - ) - ], - ), - SizedBox(height: 20.h), - Text('가죽쪼리 250 팔아요', //title - style: TextStyle(fontSize: 16.spMin), - ), - SizedBox(height: 5.h),//제목 - Text('25,000원', //price - style: TextStyle(fontSize: 16.spMin, - fontWeight: FontWeight.w700), - ), //가격 - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - SvgPicture.asset( - 'assets/icon/ICON_good.svg', - width: 16.r, - height: 16.r, - color: Color(0xffc1c1c1) - ), - Text(' 10 ',//likeCount - style: TextStyle( - fontSize: 14.spMin, - color: Color(0xffc1c1c1) - ), - ), - SvgPicture.asset( - 'assets/icon/icon_comment.svg', - width: 16.r, - height: 16.r, - color: Color(0xffc1c1c1) - ), - Text(' 10',//commentCount - style: TextStyle( - fontSize: 14.spMin, - color: Color(0xffc1c1c1) + ); + }, + child: SvgPicture.asset( + 'assets/icon/ICON_more.svg', + width: 16.r, + height: 16.r, ), ), ], - ) - ], + ), + ], ), - ) //물건 설명 - - ], - ) + SizedBox(height: 20.h), + Text( + marketBoard.title ?? "", // 제목 정보 사용 + style: TextStyle(fontSize: 16.spMin), + ), + SizedBox(height: 5.h), + Text( + '${marketBoard.price ?? 0}원', // 가격 정보 사용 + style: TextStyle( + fontSize: 16.spMin, fontWeight: FontWeight.w700), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SvgPicture.asset( + 'assets/icon/ICON_good.svg', + width: 16.r, + height: 16.r, + color: Color(0xffc1c1c1), + ), + Text( + ' ${marketBoard.marketArticleBookmarkCount ?? 0} ', + style: TextStyle( + fontSize: 14.spMin, + color: Color(0xffc1c1c1), + ), + ), + SvgPicture.asset( + 'assets/icon/icon_comment.svg', + width: 16.r, + height: 16.r, + color: Color(0xffc1c1c1), + ), + Text( + ' ${marketBoard.commentsCount ?? 0}', + style: TextStyle( + fontSize: 14.spMin, + color: Color(0xffc1c1c1), + ), + ), + ], + ), + ], + ), + ), + ], ), - ); - }, - separatorBuilder: (BuildContext context, int index){ - return Container( - height: 1.h, color: Color(0xffE5EBFF), - ); - }, - itemCount:10 + ), + ); + }, + separatorBuilder: (BuildContext context, int index) { + return Container( + height: 1.h, + color: Color(0xffE5EBFF), + ); + }, + itemCount: marketBoardList.length, ); - } + } diff --git a/lib/views/pages/board/market_detail_page.dart b/lib/views/pages/board/market_detail_page.dart index 052bec6a..eb4ea55a 100644 --- a/lib/views/pages/board/market_detail_page.dart +++ b/lib/views/pages/board/market_detail_page.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:aliens/mockdatas/board_mockdata.dart'; import 'package:aliens/models/chatRoom_model.dart'; +import 'package:aliens/models/market_articles.dart'; import 'package:aliens/models/screenArgument.dart'; import 'package:aliens/repository/sql_message_database.dart'; import 'package:aliens/views/pages/chatting/chatting_page.dart'; @@ -26,8 +27,10 @@ import '../home_page.dart'; class MarketDetailPage extends StatefulWidget { const MarketDetailPage( - {super.key, required this.screenArguments}); + {super.key, required this.screenArguments, required this.marketBoard}); final ScreenArguments screenArguments; + final MarketBoard marketBoard; + @override @@ -73,7 +76,7 @@ class _MarketDetailPageState extends State { List whatStatus = [ '미개봉', '거의 새 것', '약간의 하자', '사용감 있음' ]; - String productStatus = '거의 새 것'; + String productStatus = '${widget.marketBoard.productStatus}'; return GestureDetector( onTap: (){ FocusScope.of(context).unfocus(); @@ -141,7 +144,7 @@ class _MarketDetailPageState extends State { children: [ Expanded( child: Text( - '가죽쪼리팔아요', + '${widget.marketBoard.title}', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 20.spMin, @@ -160,7 +163,7 @@ class _MarketDetailPageState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text('판매중', + Text('${widget.marketBoard.status}', textAlign: TextAlign.center, style: TextStyle( color: Color(0xff888888), @@ -169,9 +172,7 @@ class _MarketDetailPageState extends State { ), ], ), - ), - ], ),//제목 넣는 곳 SizedBox(height: MediaQuery.of(context).size.height*0.01,), @@ -182,7 +183,7 @@ class _MarketDetailPageState extends State { Text('₩ ', style: TextStyle(fontSize: 16.spMin,fontWeight: FontWeight.bold), ), - Text('25000', + Text('${widget.marketBoard.price}', style: TextStyle(fontSize: 16.spMin,fontWeight: FontWeight.bold), )//가격넣는곳 ], @@ -193,7 +194,7 @@ class _MarketDetailPageState extends State { Row( children: [ Text( - '상품상태', + 'market-productStatus'.tr(), style: TextStyle( fontSize: 16.spMin, color: Color(0xff888888), @@ -253,21 +254,8 @@ class _MarketDetailPageState extends State { SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( - children: [ - Container( - margin: EdgeInsets.only(right: 20).r, - width: 197.spMin, - height: 207.spMin, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10).r, - color: Color(0xffF8F8F8), - ), - child: Icon(Icons.add_photo_alternate_outlined,//사진 넣는 곳 - size: 66.spMin, - color: Color(0xffebebeb), - ), - ), - Container( + children: widget.marketBoard.imageUrls!.map((imageUrl) { + return Container( margin: EdgeInsets.only(right: 20).r, width: 197.spMin, height: 207.spMin, @@ -275,29 +263,18 @@ class _MarketDetailPageState extends State { borderRadius: BorderRadius.circular(10).r, color: Color(0xffF8F8F8), ), - child: Icon(Icons.add_photo_alternate_outlined,//사진 넣는 곳 - size: 66.spMin, - color: Color(0xffebebeb), + child: Image.network( + imageUrl, + fit: BoxFit.cover, ), - ), - Container( - width: 197.spMin, - height: 207.spMin, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10).r, - color: Color(0xffF8F8F8), - ), - child: Icon(Icons.add_photo_alternate_outlined,//사진 넣는 곳 - size: 66.h, - color: Color(0xffebebeb), - ), - ) - ], + ); + }).toList(), ), - ),//사진 + ), +//사진 SizedBox(height: MediaQuery.of(context).size.height*0.02), Text( - '제품명 : 가죽쪼리\n가격 : 25,000원\n상세정보 : 거의 새 상품이나 마찬가지입니다.\n딱 한 번만 신었어요\n휴대폰 번호 : 010-1234-5678', //내용 + '${widget.marketBoard.content}', //내용 textAlign: TextAlign.start, style: TextStyle( fontSize: 16.spMin @@ -308,7 +285,7 @@ class _MarketDetailPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text('23.08.06 22:10',//createdAt + Text('${widget.marketBoard.createdAt}',//createdAt style: TextStyle( color: Color(0xffa8a8a8), fontSize: 16.spMin, @@ -318,15 +295,16 @@ class _MarketDetailPageState extends State { children: [ Padding( padding: const EdgeInsets.all(4.0).r, - child: Icon( - Icons.thumb_up_alt_sharp, + child: SvgPicture.asset( + 'assets/icon/ICON_good.svg', + width: 18.r, + height: 18.r, color: Color(0xffc1c1c1), - size: 18.spMin, ), ), Padding( padding: EdgeInsets.only(left: 4, right: 15).r, - child: Text('10', + child: Text('${widget.marketBoard.marketArticleBookmarkCount}', style: TextStyle( fontSize: 16.spMin, color: Color(0xffc1c1c1) @@ -335,15 +313,16 @@ class _MarketDetailPageState extends State { ), Padding( padding: const EdgeInsets.all(4.0).r, - child: Icon( - Icons.chat_bubble, + child: SvgPicture.asset( + 'assets/icon/icon_comment.svg', + width: 18.r, + height: 18.r, color: Color(0xffc1c1c1), - size: 18.spMin, ), ), Padding( padding: const EdgeInsets.all(4.0).r, - child: Text('1', + child: Text('${widget.marketBoard.commentsCount}', style: TextStyle( fontSize: 16.spMin, color: Color(0xffc1c1c1) diff --git a/lib/views/pages/board/market_posting_board_page.dart b/lib/views/pages/board/market_posting_board_page.dart index 5aaf3aee..753be1b7 100644 --- a/lib/views/pages/board/market_posting_board_page.dart +++ b/lib/views/pages/board/market_posting_board_page.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; +import 'package:aliens/models/market_articles.dart'; import 'package:aliens/permissions.dart'; import 'package:chips_choice/chips_choice.dart'; import 'package:aliens/models/chatRoom_model.dart'; @@ -22,8 +23,9 @@ import '../../components/button.dart'; class MarketBoardPostPage extends StatefulWidget { - const MarketBoardPostPage({super.key,required this.screenArguments}); + const MarketBoardPostPage({super.key,required this.screenArguments, this.marketBoard, }); final ScreenArguments screenArguments; +final MarketBoard? marketBoard; @override From 0aa35e6489ceee0aa7151a368a29d04e5cc6335d Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Mon, 4 Sep 2023 01:26:34 +0900 Subject: [PATCH 04/10] =?UTF-8?q?=EB=8C=93=EA=B8=80=20=EC=A1=B0=ED=9A=8C,?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/translations/en-US.json | 7 +- assets/translations/ko-KR.json | 7 +- lib/apis/apis.dart | 32 +- lib/models/market_comment.dart | 70 ++++ lib/providers/market_comment_provider.dart | 69 ++++ .../components/marketcomment_dialog.dart | 201 +++++++++++ lib/views/pages/board/market_board_page.dart | 5 +- lib/views/pages/board/market_detail_page.dart | 334 ++++++++++-------- .../board/market_posting_board_page.dart | 51 ++- 9 files changed, 590 insertions(+), 186 deletions(-) create mode 100644 lib/models/market_comment.dart create mode 100644 lib/providers/market_comment_provider.dart create mode 100644 lib/views/components/marketcomment_dialog.dart diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index d2a61ffe..1272de83 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -299,6 +299,11 @@ "general-board-post" : "General Board New Post", - "market-board-post": "Market Board New Post" + "market-board-post": "Market Board New Post", + "Brand_New": "Brand New", + "Almost_New": "Almost New", + "Slight_Defect": "Slight Defect", + "Used": "Used", + "sale": "For sale" } \ No newline at end of file diff --git a/assets/translations/ko-KR.json b/assets/translations/ko-KR.json index 478263ff..94cab56b 100644 --- a/assets/translations/ko-KR.json +++ b/assets/translations/ko-KR.json @@ -301,5 +301,10 @@ "post4": "카테고리를 선택해주세요.", "general-board-post" : "일반게시판 글쓰기", - "market-board-post": "장터게시판 글쓰기" + "market-board-post": "장터게시판 글쓰기", + "Brand_New": "미개봉", + "Almost_New": "거의 새 것", + "Slight_Defect": "약간의 하자", + "Used": "사용감 있음", + "sale": "판매중" } \ No newline at end of file diff --git a/lib/apis/apis.dart b/lib/apis/apis.dart index b47412b5..e80cfd9b 100644 --- a/lib/apis/apis.dart +++ b/lib/apis/apis.dart @@ -21,6 +21,7 @@ import 'dart:convert'; import '../models/board_model.dart'; import '../models/comment_model.dart'; import '../models/market_articles.dart'; +import '../models/market_comment.dart'; import '../models/memberDetails_model.dart'; import '../models/message_model.dart'; import '../models/partner_model.dart'; @@ -2135,7 +2136,7 @@ class APIs { /*상품 판매글 댓글 전체 조회*/ - static Future> getMarketArticleComments(int marketArticleId) async { + static Future> getMarketArticleComments(int marketArticleId) async { try { var jwtToken = await storage.read(key: 'token'); final accessToken = json.decode(jwtToken!)['data']['accessToken']; @@ -2151,15 +2152,9 @@ class APIs { ); if (response.statusCode == 200) { - final responseBody = json.decode(utf8.decode(response.bodyBytes)); - final commentsData = responseBody['data']; - - // 댓글 데이터를 파싱하여 Comment 객체로 변환 - final comments = commentsData.map((commentJson) { - return Comment.fromJson(commentJson); - }).toList(); - - return comments; + print(json.decode(utf8.decode(response.bodyBytes))); + List body = json.decode(utf8.decode(response.bodyBytes))['data']; + return body.map((dynamic item) => MarketComment.fromJson(item)).toList(); } else { final responseBody = json.decode(utf8.decode(response.bodyBytes)); final errorCode = responseBody['code']; @@ -2180,12 +2175,12 @@ class APIs { /*상품 판매글 부모 댓글 등록*/ - static Future createMarketArticleComment(int marketArticleId, String content) async { + static Future createMarketArticleComment(int articleCommentId, String content) async { try { var jwtToken = await storage.read(key: 'token'); final accessToken = json.decode(jwtToken!)['data']['accessToken']; - final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$marketArticleId/market-article-comments'); + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$articleCommentId/market-article-comments'); final response = await http.post( url, @@ -2197,9 +2192,8 @@ class APIs { ); if (response.statusCode == 201) { - final responseBody = json.decode(utf8.decode(response.bodyBytes)); - final message = responseBody['message']; - return message; + print(json.decode(utf8.decode(response.bodyBytes))); + return true; } else { final responseBody = json.decode(utf8.decode(response.bodyBytes)); final errorCode = responseBody['code']; @@ -2220,12 +2214,12 @@ class APIs { /*특정 판매글 댓글 삭제*/ - static Future deleteMarketArticleComment(int marketArticleCommentId) async { + static Future deleteMarketArticleComment(int articleCommentId) async { try { var jwtToken = await storage.read(key: 'token'); final accessToken = json.decode(jwtToken!)['data']['accessToken']; - final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-article-comments/$marketArticleCommentId'); + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-article-comments/$articleCommentId'); final response = await http.delete( url, @@ -2259,12 +2253,12 @@ class APIs { /*특정 상품 판매글 댓글에 대댓글 등록*/ - static Future addMarketArticleCommentReply(int marketArticleId, int marketArticleCommentId, String content) async { + static Future addMarketArticleCommentReply(int articleCommentId, int ArticleCommentId, String content) async { try { var jwtToken = await storage.read(key: 'token'); final accessToken = json.decode(jwtToken!)['data']['accessToken']; - final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$marketArticleId/market-article-comments/$marketArticleCommentId'); + final url = Uri.parse('http://3.34.2.246:8080/api/v2/market-articles/$articleCommentId/market-article-comments/$ArticleCommentId'); final response = await http.post( url, diff --git a/lib/models/market_comment.dart b/lib/models/market_comment.dart new file mode 100644 index 00000000..2cca9592 --- /dev/null +++ b/lib/models/market_comment.dart @@ -0,0 +1,70 @@ +class MarketComment { + int? articleCommentId; + String? content; + MarketCommentMember? member; + String? createdAt; + List? childs; + + MarketComment({this.articleCommentId, this.content, this.member, this.childs, this.createdAt}); + + MarketComment.fromJson(Map json) { + List childComments = []; + if (json['childs'] != null) { + var childJsonList = json['childs'] as List; + childComments = childJsonList + .map((childJson) => MarketComment.fromJson(childJson)) + .toList(); + } + + articleCommentId = json['articleCommentId']; + content = json['content']; + createdAt = json['createdAt']; + member = json['member'] != null ? new MarketCommentMember.fromJson(json['member']) : null; + childs = childComments; + } + + Map toJson() { + final Map data = new Map(); + data['articleCommentId'] = this.articleCommentId; + data['content'] = this.content; + data['childs'] = this.childs; + data['createdAt'] = this.createdAt; + if (this.member != null) { + data['member'] = this.member!.toJson(); + } + return data; + } +} + +class MarketCommentMember { + int? memberId; + String? email; + String? name; + String? profileImageUrl; + String? nationality; + + MarketCommentMember( + {this.memberId, + this.email, + this.name, + this.profileImageUrl, + this.nationality}); + + MarketCommentMember.fromJson(Map json) { + memberId = json['memberId']; + email = json['email']; + name = json['name']; + profileImageUrl = json['profileImageUrl']; + nationality = json['nationality']; + } + + Map toJson() { + final Map data = new Map(); + data['memberId'] = this.memberId; + data['email'] = this.email; + data['name'] = this.name; + data['profileImageUrl'] = this.profileImageUrl; + data['nationality'] = this.nationality; + return data; + } +} diff --git a/lib/providers/market_comment_provider.dart b/lib/providers/market_comment_provider.dart new file mode 100644 index 00000000..e667f686 --- /dev/null +++ b/lib/providers/market_comment_provider.dart @@ -0,0 +1,69 @@ +import 'package:aliens/mockdatas/board_mockdata.dart'; +import 'package:aliens/models/board_model.dart'; +import 'package:flutter/widgets.dart'; +import 'package:provider/provider.dart'; + +import '../apis/apis.dart'; +import '../models/comment_model.dart'; +import '../models/market_comment.dart'; + +class MarketCommentProvider with ChangeNotifier { + + + List? commentListData; + bool loading = false; + MarketComment? marketcomment; + + getMarketComments(int articleCommentId) async { + loading = true; + try { + commentListData = await APIs.getMarketArticleComments(articleCommentId); + } catch (e) { + if (e == "AT-C-002") { + await APIs.getAccessToken(); + commentListData = await APIs.getMarketArticleComments(articleCommentId); + } else { + // 오류 처리 로직 + } + } + loading = false; + notifyListeners(); + } + + + addMarketComment(int articleId, String content) async { + try { + await APIs.createMarketArticleComment(articleId, content); + } catch (e) { + if (e == "AT-C-002") { + await APIs.getAccessToken(); + await APIs.createMarketArticleComment(articleId, content); + } else { + return false; + } + } + //TODO fcm 전송 + + + notifyListeners(); + return true; + } + + addNestedMarketComment(int commentId, int ArticleCommentId, String content) async { + try { + await APIs.addMarketArticleCommentReply(commentId, ArticleCommentId, content); + } catch (e) { + if (e == "AT-C-002") { + await APIs.getAccessToken(); + await APIs.addMarketArticleCommentReply(commentId, ArticleCommentId, content); + } else { + return false; + } + } + //TODO fcm 전송 + + + notifyListeners(); + return true; + } +} \ No newline at end of file diff --git a/lib/views/components/marketcomment_dialog.dart b/lib/views/components/marketcomment_dialog.dart new file mode 100644 index 00000000..7f9e8a4c --- /dev/null +++ b/lib/views/components/marketcomment_dialog.dart @@ -0,0 +1,201 @@ +import 'package:aliens/models/partner_model.dart'; +import 'package:aliens/models/screenArgument.dart'; +import 'package:aliens/views/components/block_dialog_widget.dart'; +import 'package:aliens/views/components/report_dialog_widget.dart'; +import 'package:aliens/views/components/report_iOS_dialog_widget.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; +import 'dart:io' show Platform; + +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:provider/provider.dart'; + +import '../../models/comment_model.dart'; +import '../../models/market_comment.dart'; +import '../../providers/comment_provider.dart'; +import '../../providers/market_comment_provider.dart'; + + +class MarketCommentDialog extends StatelessWidget{ + final BuildContext context; + final VoidCallback onpressed; + final bool isNestedComment; + final MarketComment marketcomment; + + const MarketCommentDialog({ + Key? key, + required this.context, + required this.onpressed, + required this.isNestedComment, + required this.marketcomment + }) : super(key:key); + + @override + Widget build(BuildContext context) { + if(Platform.isAndroid) + return androidDialog(); + else + return iOSDialog(); + } + + Widget androidDialog(){ + final marketcommentProvider = Provider.of(context); + return Dialog( + elevation: 0, + backgroundColor: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0).r, + ), + child: Container( + padding: EdgeInsets.all(30).r, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'chatting-dialog1'.tr(), + style: TextStyle( + fontSize: 16.spMin, + fontWeight: FontWeight.bold), + ), + SizedBox( + height: 20.h, + ), + isNestedComment ? SizedBox(): + InkWell( + onTap: onpressed, + child: Container( + padding: EdgeInsets.all(13).r, + decoration: BoxDecoration( + color: Color(0xff7898FF), + borderRadius: BorderRadius.circular(5).r), + alignment: Alignment.center, + child: Text('comment3'.tr(), + style: TextStyle(color: Colors.white), + ), + ), + ), + SizedBox( + height: 10.h, + ), + InkWell( + onTap: (){ + //TODO 로딩 만들기 + marketcommentProvider.deleteComment(marketcomment.articleCommentId!); + }, + child: Container( + padding: EdgeInsets.all(13).r, + decoration: BoxDecoration( + color: Color(0xff7898FF), + borderRadius: BorderRadius.circular(5).r), + alignment: Alignment.center, + child: Text('delete'.tr(), + style: TextStyle(color: Colors.white), + ), + ), + ), + SizedBox( + height: 10.h, + ), + InkWell( + onTap: (){ + Navigator.pop(context); + showDialog( + context: context, + builder: (builder) => ReportDialog(partner: Partner(), context: context)); + + }, + child: Container( + padding: EdgeInsets.all(13).r, + decoration: BoxDecoration( + color: Color(0xff7898FF), + borderRadius: BorderRadius.circular(5).r), + alignment: Alignment.center, + child: Text('chatting-report1'.tr(), + style: TextStyle(color: Colors.white), + ), + ), + ) + ], + ), + ), + ); + } + + Widget iOSDialog(){ + final marketcommentProvider = Provider.of(context); + return Dialog( + elevation: 0, + backgroundColor: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + isNestedComment ? SizedBox(): + InkWell( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20.0), + topRight: Radius.circular(20.0), + ), + onTap: onpressed, + child: Container( + height: 80, + alignment: Alignment.center, + child: Text( + "comment3".tr(), + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + InkWell( + onTap: () { + //TODO 로딩 만들기 + marketcommentProvider.deleteComment(marketcomment.articleCommentId!); + }, + child: Container( + height: 80, + alignment: Alignment.center, + child: Text( + "delete".tr(), + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + InkWell( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(20.0), + bottomRight: Radius.circular(20.0), + ), + onTap: () { + Navigator.pop(context); + showDialog( + context: context, + builder: (builder) => iOSReportDialog()); + }, + child: Container( + height: 80, + alignment: Alignment.center, + child: Text( + "chatting-report1".tr(), + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ); + } + +} + diff --git a/lib/views/pages/board/market_board_page.dart b/lib/views/pages/board/market_board_page.dart index 2a259df7..b2dcae93 100644 --- a/lib/views/pages/board/market_board_page.dart +++ b/lib/views/pages/board/market_board_page.dart @@ -14,6 +14,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../../models/market_articles.dart'; +import '../../../models/message_model.dart'; import '../../components/board_drawer_widget.dart'; @@ -259,7 +260,7 @@ class _MarketBoardPageState extends State { mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - marketBoard.createdAt ?? "", // 생성 날짜 정보 사용 + DataUtils.getTime(widget.marketBoard?.createdAt), // 생성 날짜 정보 사용 style: TextStyle( color: Color(0xffC1C1C1), fontSize: 12.spMin, @@ -307,7 +308,7 @@ class _MarketBoardPageState extends State { ), SizedBox(height: 5.h), Text( - '${marketBoard.price ?? 0}원', // 가격 정보 사용 + '${marketBoard.price.toString() ?? 0}원', // 가격 정보 사용 style: TextStyle( fontSize: 16.spMin, fontWeight: FontWeight.w700), ), diff --git a/lib/views/pages/board/market_detail_page.dart b/lib/views/pages/board/market_detail_page.dart index eb4ea55a..fe0e3f6e 100644 --- a/lib/views/pages/board/market_detail_page.dart +++ b/lib/views/pages/board/market_detail_page.dart @@ -12,6 +12,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_neumorphic/flutter_neumorphic.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:provider/provider.dart'; import '../../../mockdatas/comment_mockdata.dart'; import '../../../mockdatas/market_comment_mockdata.dart'; import '../../../models/comment_model.dart'; @@ -19,10 +20,13 @@ import '../../../models/board_model.dart'; import '../../../models/countries.dart'; import 'package:flutter/services.dart'; +import '../../../models/market_comment.dart'; import '../../../models/message_model.dart'; +import '../../../providers/market_comment_provider.dart'; import '../../components/board_dialog_widget.dart'; import '../../components/board_drawer_widget.dart'; import '../../components/comment_dialog_widget.dart'; +import '../../components/marketcomment_dialog.dart'; import '../home_page.dart'; class MarketDetailPage extends StatefulWidget { @@ -33,6 +37,7 @@ class MarketDetailPage extends StatefulWidget { + @override State createState() => _MarketDetailPageState(); } @@ -55,7 +60,7 @@ class _MarketDetailPageState extends State { }); FocusScope.of(context).unfocus(); } - + String getNationCode(_nationality){ var nationCode = ''; for (Map country in countries) { @@ -74,9 +79,11 @@ class _MarketDetailPageState extends State { final bool isSmallScreen = screenWidth <= 700; List whatStatus = [ - '미개봉', '거의 새 것', '약간의 하자', '사용감 있음' + 'Brand_New'.tr(), 'Almost_New'.tr(), 'Slight_Defect'.tr(), 'Used'.tr() ]; String productStatus = '${widget.marketBoard.productStatus}'; + final marketcommentProvider = Provider.of(context, listen: false); + marketcommentProvider.getMarketComments(widget.marketBoard.articleId!); return GestureDetector( onTap: (){ FocusScope.of(context).unfocus(); @@ -183,7 +190,7 @@ class _MarketDetailPageState extends State { Text('₩ ', style: TextStyle(fontSize: 16.spMin,fontWeight: FontWeight.bold), ), - Text('${widget.marketBoard.price}', + Text('${widget.marketBoard.price.toString()}', style: TextStyle(fontSize: 16.spMin,fontWeight: FontWeight.bold), )//가격넣는곳 ], @@ -285,7 +292,8 @@ class _MarketDetailPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text('${widget.marketBoard.createdAt}',//createdAt + Text( + DataUtils.getTime(widget.marketBoard.createdAt),//createdAt style: TextStyle( color: Color(0xffa8a8a8), fontSize: 16.spMin, @@ -336,188 +344,212 @@ class _MarketDetailPageState extends State { Divider(thickness: 1.2.h,color: Color(0xffE5EBFF),), //댓글 - for (int i = 0; i < MarketcommentListMock.length; i++) - Column( - children: [ - Padding( - padding: EdgeInsets.symmetric(vertical: 15, /*horizontal: 30*/).r, + marketcommentProvider.loading? + Container( + alignment: Alignment.center, + child: Image( + image: AssetImage( + "assets/illustration/loading_01.gif"))) + : + Column( + children: [ + for(int index = 0; index < 5; index++) + Container( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only(right: 10.0).r, - child: SvgPicture.asset( - 'assets/icon/icon_profile.svg', - width: 25.r, - color: Color(0xffc1c1c1), - ), - ), - Text( - '${MarketcommentListMock[i].member!.name}', - style: TextStyle( - fontWeight: FontWeight.bold, fontSize: 14.spMin), - ), - Text( - '/', - style: TextStyle( - fontWeight: FontWeight.bold, fontSize: 14.spMin), - ), - Text( - getNationCode(MarketcommentListMock[i].member!.nationality), - style: TextStyle( - fontWeight: FontWeight.bold, fontSize: 14.spMin), - ) - ], - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - - Text( - DataUtils.getTime(MarketcommentListMock[i].createdAt), - style: TextStyle( - fontSize: 12.spMin, color: Color(0xffc1c1c1)), - ), - InkWell( - onTap: (){ - showDialog(context: context, builder: (builder){ - return CommentDialog(context: context, onpressed: (){ - setState(() { - isNestedComments = true; - parentsCommentIndex = i; - }); - Navigator.pop(context); - }, - isNestedComment: false, - comment: MarketcommentListMock[i], - ); - }); - }, - child: Padding( - padding: const EdgeInsets.only(left: 8.0).r, - child: Icon(Icons.more_vert, - color: Color(0xffc1c1c1)), - ), - ) - ], - ) - ], - mainAxisAlignment: MainAxisAlignment.spaceBetween, - ), Padding( - padding: const EdgeInsets.only( - top: 13).r, - child: Text( - '${MarketcommentListMock[i].content}', - style: TextStyle(fontSize: 14.spMin, color: Color(0xff616161)), - ), - ), - ], - ), - ), - - //대댓글 - MarketcommentListMock[i].childs == null ? SizedBox() : - Column( - children: [ - for(int j = 0 ; j < MarketcommentListMock[i].childs!.length; j++) - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Container( - // padding: EdgeInsets.all(10).r, - alignment: Alignment.centerRight, - child: Icon( - Icons.subdirectory_arrow_right, - size: 20.h, - color: Color(0xffc1c1c1), - ), - ), - ), - Container( - decoration: BoxDecoration( - color: Color(0xffF4F4F4), - borderRadius: BorderRadius.circular(10).r, - ), - width: 300.w, - padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 20.w), - margin: EdgeInsets.only(top: 15.h, bottom: 0.h, right: 30.w, left: 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + padding: EdgeInsets.symmetric(vertical: 15, horizontal: 30).r, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( children: [ Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, children: [ Padding( - padding: const EdgeInsets.only(right: 10.0).w, + padding: const EdgeInsets.only(right: 10.0).r, child: SvgPicture.asset( 'assets/icon/icon_profile.svg', width: 25.r, color: Color(0xffc1c1c1), ), ), - Flexible( - child: Container( - alignment: Alignment.centerLeft, - padding: EdgeInsets.only(right: 10), - child: Text( - '${MarketcommentListMock[i].childs![j].member!.name}/${getNationCode(MarketcommentListMock[i].childs![j].member!.nationality)}', - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.bold, fontSize: 14.spMin), - ), - ), + Text( + '${marketcommentProvider.commentListData![index].member!.name}', + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14.spMin), ), Text( - DataUtils.getTime(MarketcommentListMock[i].childs![j].createdAt), + '/', + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14.spMin), + ), + Text( + getNationCode(marketcommentProvider.commentListData![index].member!.nationality), + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14.spMin), + ) + ], + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + + Text( + DataUtils.getTime(marketcommentProvider.commentListData![index].createdAt), style: TextStyle( fontSize: 12.spMin, color: Color(0xffc1c1c1)), ), InkWell( onTap: (){ + + print(marketcommentProvider.commentListData!); showDialog(context: context, builder: (builder){ - return CommentDialog(context: context, onpressed: (){ + return MarketCommentDialog(context: context, onpressed: (){ setState(() { isNestedComments = true; + parentsCommentIndex = index; }); Navigator.pop(context); }, - isNestedComment: true, - comment: MarketcommentListMock[i],); + isNestedComment: false, marketcomment: marketcomment); }); }, child: Padding( - padding: const EdgeInsets.only(left: 8.0).w, - child: Icon(Icons.more_vert, - color: Color(0xffc1c1c1)), + padding: const EdgeInsets.only(left: 8.0).r, + child: SvgPicture.asset( + 'assets/icon/ICON_more.svg', + width: 25.r, + height: 25.r, + color: Color(0xffc1c1c1), + ), ), ) ], + ) + ], + mainAxisAlignment: MainAxisAlignment.spaceBetween, + ), + Padding( + padding: const EdgeInsets.only( + top: 13).r, + child: Text( + '${marketcommentProvider.commentListData![index].content}', + style: TextStyle(fontSize: 14.spMin, color: Color(0xff616161)), + ), + ), + ], + ), + ), + + //대댓글 + marketcommentProvider.commentListData![index].childs == null ? SizedBox() : + Column( + children: [ + for(int j = 0 ; j < marketcommentProvider.commentListData![index].childs!.length; j++) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Container( + padding: EdgeInsets.all(10).r, + alignment: Alignment.centerRight, + child: SvgPicture.asset( + 'assets/icon/ICON_reply.svg', + width: 15.r, + height: 15.r, + color: Color(0xffc1c1c1), + ), + ), ), - Padding( - padding: const EdgeInsets.only( - top: 5).h, - child: Text( - '${MarketcommentListMock[i].childs![j].content}', - style: TextStyle(fontSize: 14.spMin, color: Color(0xff616161)), + Container( + decoration: BoxDecoration( + color: Color(0xffF4F4F4), + borderRadius: BorderRadius.circular(10).r, + ), + width: 300.w, + padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 20.w), + margin: EdgeInsets.only(top: 15.h, bottom: 0.h, right: 30.w, left: 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(right: 10.0).w, + child: SvgPicture.asset( + 'assets/icon/icon_profile.svg', + width: 25.r, + color: Color(0xffc1c1c1), + ), + ), + Flexible( + child: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(right: 10), + child: Text( + '${marketcommentProvider.commentListData![index].childs![j].member!.name}/${getNationCode(marketcommentProvider.commentListData![index].childs![j].member!.nationality)}', + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14.spMin), + ), + ), + ), + Text( + DataUtils.getTime(marketcommentProvider.commentListData![index].childs![j].createdAt), + style: TextStyle( + fontSize: 12.spMin, color: Color(0xffc1c1c1)), + ), + InkWell( + onTap: (){ + showDialog(context: context, builder: (builder){ + return MarketCommentDialog(context: context, onpressed: (){ + setState(() { + isNestedComments = true; + }); + Navigator.pop(context); + }, + isNestedComment: true, marketcomment:marketComment); + }); + }, + child: Padding( + padding: const EdgeInsets.only(left: 8.0).w, + child: SvgPicture.asset( + 'assets/icon/ICON_more.svg', + width: 22.r, + height: 22.r, + color: Color(0xffc1c1c1), + ), + ), + ) + ], + ), + Padding( + padding: const EdgeInsets.only( + top: 5).h, + child: Text( + '${marketcommentProvider.commentListData![index].childs![j].content}', + style: TextStyle(fontSize: 14.spMin, color: Color(0xff616161)), + ), + ), + ], ), ), ], ), - ), ], ), - ], - ), - Divider(thickness: 1.5, color: Color(0xfff8f8f8),) - ], - ), + Divider(thickness: 1.5, color: Color(0xfff8f8f8),) + + + ], + ), + ) + ], + ) + ], ), ), @@ -561,12 +593,12 @@ class _MarketDetailPageState extends State { IconButton( onPressed: () { if(isNestedComments){ - Comment newValue = Comment( + MarketComment newValue = MarketComment( articleCommentId: 1, content: _newComment, createdAt: DateTime.now().toString(), childs: [], - member: CommentMember( + member: MarketCommentMember( name: "daisy", nationality: "Japan", profileImageUrl: "" @@ -577,12 +609,12 @@ class _MarketDetailPageState extends State { isNestedComments = false; } else{ - Comment newValue = Comment( + MarketComment newValue = MarketComment( articleCommentId: 1, content: _newComment, createdAt: DateTime.now().toString(), childs: [], - member: CommentMember( + member: MarketCommentMember( name: "daisy", nationality: "Japan", profileImageUrl: "" diff --git a/lib/views/pages/board/market_posting_board_page.dart b/lib/views/pages/board/market_posting_board_page.dart index 753be1b7..8e44b5f7 100644 --- a/lib/views/pages/board/market_posting_board_page.dart +++ b/lib/views/pages/board/market_posting_board_page.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; +import 'package:aliens/apis/apis.dart'; import 'package:aliens/models/market_articles.dart'; import 'package:aliens/permissions.dart'; import 'package:chips_choice/chips_choice.dart'; @@ -40,7 +41,7 @@ class _MarketBoardPostPageState extends State { String _price = ''; String _content = ''; List whatStatus = [ - '미개봉', '거의 새 것', '약간의 하자', '사용감 있음' + 'Brand_New'.tr(), 'Almost_New'.tr(), 'Slight_Defect'.tr(), 'Used'.tr() ]; String productStatus = ''; @@ -157,7 +158,7 @@ class _MarketBoardPostPageState extends State { Container( width: double.infinity, color: Colors.white, - padding: EdgeInsets.only(right: 10.w, left: 10.w, top: 12.h, bottom: 50), + padding: EdgeInsets.only(right: 10.w, left: 10.w, top: 12.h, bottom: 50.h), child: Form( key: _formKey, child: Column( @@ -167,7 +168,7 @@ class _MarketBoardPostPageState extends State { Expanded( child: TextFormField( style: TextStyle( - fontSize: 20.h, + fontSize: 20.spMin, color: Color(0xff616161) ), decoration: InputDecoration( @@ -218,7 +219,7 @@ class _MarketBoardPostPageState extends State { height: 4.r, color: Color(0xff888888), ), - Text('판매중', + Text('sale'.tr(), style: TextStyle( color: Color(0xff888888), fontSize:14.spMin @@ -276,7 +277,7 @@ class _MarketBoardPostPageState extends State { Padding( padding: EdgeInsets.symmetric(horizontal: 14), child: Text( - '상품상태', + 'market-productStatus'.tr(), style: TextStyle( fontSize: 16.spMin, color: Color(0xff888888), @@ -298,9 +299,7 @@ class _MarketBoardPostPageState extends State { label: Text( condition, style: TextStyle( - fontSize: isSmallScreen - ? 10 - : 12, + fontSize: 12.spMin, color: isSelected ? Colors.white : Color(0xffC1C1C1), @@ -317,7 +316,7 @@ class _MarketBoardPostPageState extends State { }); }, labelPadding: EdgeInsets.only( - left: 12, right: 12), + left: 12.w, right: 12.w), // 선택 영역 패딩 조절 shape: RoundedRectangleBorder( side: BorderSide( @@ -387,7 +386,7 @@ class _MarketBoardPostPageState extends State { decoration: InputDecoration( hintText: '${'market-posting-content'.tr()}', hintStyle: TextStyle( - fontSize: 14.h, + fontSize: 14.spMin, color: Color(0xffC0C0C0) ), enabledBorder: UnderlineInputBorder( @@ -416,10 +415,38 @@ class _MarketBoardPostPageState extends State { Button( child: Text( 'post3'.tr(), style: TextStyle(color: _isButtonEnabled ? Colors.white : Color(0xff888888))), - onPressed: () { - if (_formKey.currentState!.validate()) { + onPressed: () async { + if (_formKey.currentState!.validate() && productStatus.isNotEmpty && _images.isNotEmpty) { FocusScope.of(context).unfocus(); _formKey.currentState!.save(); + + MarketBoard marketArticle = MarketBoard( + title: _title, + content: _content, + price: int.parse(_price), + productStatus: productStatus, + imageUrls: _images.map((image) => image.path).toList(), + ); + + try { + bool success = await APIs.createMarketArticle(marketArticle); + + if (success) { + print('게시물 생성 성공!!!'); + Navigator.of(context).pop(); // 이전 페이지로 이동 + } else { + print('게시물 생성 실패...'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Fail'), + duration: Duration(seconds: 3), + ), + ); + } + } catch (error) { + print('Error creating market article: $error'); + } + } }, isEnabled: _formKey.currentState?.validate() == true && From 6cdb0fef089cf35b34e2869bf00b3d58dece1497 Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Mon, 4 Sep 2023 01:37:45 +0900 Subject: [PATCH 05/10] =?UTF-8?q?=EB=8C=93=EA=B8=80=EC=A1=B0=ED=9A=8C,?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/views/pages/board/market_detail_page.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/views/pages/board/market_detail_page.dart b/lib/views/pages/board/market_detail_page.dart index fe0e3f6e..df5b48f2 100644 --- a/lib/views/pages/board/market_detail_page.dart +++ b/lib/views/pages/board/market_detail_page.dart @@ -84,6 +84,8 @@ class _MarketDetailPageState extends State { String productStatus = '${widget.marketBoard.productStatus}'; final marketcommentProvider = Provider.of(context, listen: false); marketcommentProvider.getMarketComments(widget.marketBoard.articleId!); + + return GestureDetector( onTap: (){ FocusScope.of(context).unfocus(); @@ -413,7 +415,7 @@ class _MarketDetailPageState extends State { }); Navigator.pop(context); }, - isNestedComment: false, marketcomment: marketcomment); + isNestedComment: false, marketcomment: marketcommentProvider.commentListData![index]); }); }, child: Padding( @@ -511,7 +513,7 @@ class _MarketDetailPageState extends State { }); Navigator.pop(context); }, - isNestedComment: true, marketcomment:marketComment); + isNestedComment: true,marketcomment: marketcommentProvider.commentListData![index]); }); }, child: Padding( From e453a530c998438e3e8ff042bea65b5126d883ab Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Tue, 5 Sep 2023 10:20:57 +0900 Subject: [PATCH 06/10] =?UTF-8?q?=EC=83=81=ED=92=88=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8,=20=EB=94=94=ED=85=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/apis/apis.dart | 2 +- lib/main.dart | 2 + lib/providers/market_comment_provider.dart | 17 ++++ .../pages/board/article_writing_page.dart | 1 + lib/views/pages/board/market_board_page.dart | 18 ++--- .../board/market_posting_board_page.dart | 78 +++++++++++-------- 6 files changed, 71 insertions(+), 47 deletions(-) diff --git a/lib/apis/apis.dart b/lib/apis/apis.dart index d2582d10..4024a516 100644 --- a/lib/apis/apis.dart +++ b/lib/apis/apis.dart @@ -2314,7 +2314,7 @@ class APIs { /*특정 판매글 댓글 삭제*/ - static Future deleteMarketArticleComment(int articleCommentId) async { + static Future deleteMarketArticleComment(int articleCommentId) async { try { var jwtToken = await storage.read(key: 'token'); final accessToken = json.decode(jwtToken!)['data']['accessToken']; diff --git a/lib/main.dart b/lib/main.dart index 62b15168..5ce42e06 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:aliens/providers/comment_provider.dart'; +import 'package:aliens/providers/market_comment_provider.dart'; import 'package:aliens/repository/board_provider.dart'; import 'package:aliens/repository/sql_message_database.dart'; import 'package:aliens/views/pages/board/market_notice_page.dart'; @@ -94,6 +95,7 @@ void main() async { providers: [ ChangeNotifierProvider(create: (_) => BoardProvider()), ChangeNotifierProvider(create: (_) => CommentProvider()), + ChangeNotifierProvider(create: (_) => MarketCommentProvider()) ], child: EasyLocalization( path: 'assets/translations', diff --git a/lib/providers/market_comment_provider.dart b/lib/providers/market_comment_provider.dart index e667f686..5d7ca29b 100644 --- a/lib/providers/market_comment_provider.dart +++ b/lib/providers/market_comment_provider.dart @@ -66,4 +66,21 @@ class MarketCommentProvider with ChangeNotifier { notifyListeners(); return true; } + deleteMarketComment(int articleId) async { + bool value = false; + loading = true; + try { + value = await APIs.deleteMarketArticleComment(articleId); + } catch (e) { + if (e == "AT-C-002") { + await APIs.getAccessToken(); + value = await APIs.deleteMarketArticleComment(articleId); + } else { + } + } + loading = false; + notifyListeners(); + return value; + } + } \ No newline at end of file diff --git a/lib/views/pages/board/article_writing_page.dart b/lib/views/pages/board/article_writing_page.dart index 2e144c32..f2ee9dd6 100644 --- a/lib/views/pages/board/article_writing_page.dart +++ b/lib/views/pages/board/article_writing_page.dart @@ -403,6 +403,7 @@ class _ArticleWritingPageState extends State { alignment: Alignment.topCenter, padding: EdgeInsets.all(20).r, child: Button( + child: Text('post3'.tr()), onPressed: () { print(boardCategory); diff --git a/lib/views/pages/board/market_board_page.dart b/lib/views/pages/board/market_board_page.dart index b2dcae93..ccbda6ef 100644 --- a/lib/views/pages/board/market_board_page.dart +++ b/lib/views/pages/board/market_board_page.dart @@ -54,10 +54,7 @@ class _MarketBoardPageState extends State { @override Widget build(BuildContext context) { - final double screenWidth = MediaQuery - .of(context) - .size - .height; + final double screenWidth = MediaQuery.of(context).size.height; final bool isSmallScreen = screenWidth <= 700; return Scaffold( appBar: AppBar( @@ -126,12 +123,8 @@ class _MarketBoardPageState extends State { Navigator.pushNamed(context, '/market/notice'); }, child: Container( - margin: EdgeInsets - .only(right: 10, left: 10, top: 10, bottom: 10) - .r, - padding: EdgeInsets - .only(right: 10, left: 10) - .r, + margin: EdgeInsets.only(right: 10, left: 10, top: 10, bottom: 10).r, + padding: EdgeInsets.only(right: 10, left: 10).r, width: double.infinity, height: 42.spMin, decoration: BoxDecoration( @@ -181,9 +174,9 @@ class _MarketBoardPageState extends State { Widget _contentWidget() { - List marketBoardList = []; return ListView.separated( + itemBuilder: (BuildContext context, int index) { MarketBoard marketBoard = marketBoardList[index]; return InkWell( @@ -260,7 +253,8 @@ class _MarketBoardPageState extends State { mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - DataUtils.getTime(widget.marketBoard?.createdAt), // 생성 날짜 정보 사용 + '${widget.marketBoard?.createdAt}', + // DataUtils.getTime(widget.marketBoard?.createdAt), // 생성 날짜 정보 사용 style: TextStyle( color: Color(0xffC1C1C1), fontSize: 12.spMin, diff --git a/lib/views/pages/board/market_posting_board_page.dart b/lib/views/pages/board/market_posting_board_page.dart index 8e44b5f7..8b50765c 100644 --- a/lib/views/pages/board/market_posting_board_page.dart +++ b/lib/views/pages/board/market_posting_board_page.dart @@ -37,9 +37,10 @@ class _MarketBoardPostPageState extends State { final GlobalKey _formKey = GlobalKey(); bool _isButtonEnabled = false; - String _title = ''; - String _price = ''; - String _content = ''; + TextEditingController _titleController = TextEditingController(); + TextEditingController _priceController = TextEditingController(); + TextEditingController _contentController = TextEditingController(); + List whatStatus = [ 'Brand_New'.tr(), 'Almost_New'.tr(), 'Slight_Defect'.tr(), 'Used'.tr() ]; @@ -188,18 +189,13 @@ class _MarketBoardPostPageState extends State { right: 14.w, left: 14.w) ), maxLength: 30, - /*validator: (value) { - if (value == null || value.isEmpty) { - return '${'market-posting-title'.tr()}'; - }else if (value.length > 30) { - return '${'market-posting-title-error'.tr()}'; - } - return null; - },*/ - onSaved: (value) { - _title = value ?? ''; - }, - ), + controller: _titleController, + onChanged: (value){ + setState(() { + _isButtonEnabled = _isFormValid(); + }); + }, + ), ), Container( width: 95.w, @@ -263,9 +259,11 @@ class _MarketBoardPostPageState extends State { ), contentPadding: EdgeInsets.only(right: 14.w, left: 14.w), ), - - onSaved: (value) { - _price = value ?? ''; + controller: _priceController, + onChanged: (value){ + setState(() { + _isButtonEnabled = _isFormValid(); + }); }, ), ), @@ -405,25 +403,31 @@ class _MarketBoardPostPageState extends State { contentPadding: EdgeInsets.only( right: 14.w, left: 14.w) ), - - onSaved: (value) { - _content = value ?? ''; + controller: _contentController, + onChanged: (value){ + setState(() { + _isButtonEnabled = _isFormValid(); + }); }, maxLines: null, ), //상품 내용 SizedBox(height: MediaQuery.of(context).size.height * 0.08), Button( - child: Text( - 'post3'.tr(), style: TextStyle(color: _isButtonEnabled ? Colors.white : Color(0xff888888))), - onPressed: () async { - if (_formKey.currentState!.validate() && productStatus.isNotEmpty && _images.isNotEmpty) { + child: Text( + 'post3'.tr(), + style: TextStyle( + color: _isButtonEnabled ? Colors.white : Color(0xff888888), + ), + ), + onPressed: () async { + if (_formKey.currentState!.validate() && productStatus.isNotEmpty && _images.isNotEmpty ) { FocusScope.of(context).unfocus(); _formKey.currentState!.save(); MarketBoard marketArticle = MarketBoard( - title: _title, - content: _content, - price: int.parse(_price), + title: _titleController.text, + content: _contentController.text, + price: int.parse(_priceController.text), productStatus: productStatus, imageUrls: _images.map((image) => image.path).toList(), ); @@ -446,13 +450,11 @@ class _MarketBoardPostPageState extends State { } catch (error) { print('Error creating market article: $error'); } - } - }, - isEnabled: _formKey.currentState?.validate() == true && - productStatus.isNotEmpty && - _images.isNotEmpty, - ) + }, + isEnabled: _isButtonEnabled + ) + ], ), @@ -462,4 +464,12 @@ class _MarketBoardPostPageState extends State { ) ); } + + bool _isFormValid() { + return _titleController.text.isNotEmpty && + _priceController.text.isNotEmpty && + _contentController.text.isNotEmpty && + productStatus.isNotEmpty && + _images.isNotEmpty; + } } From cd18112dc0e210016e734637a034331a5fabba21 Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Tue, 5 Sep 2023 16:00:01 +0900 Subject: [PATCH 07/10] =?UTF-8?q?createdAt=EC=98=A4=EB=A5=98...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/apis/apis.dart | 2 ++ lib/views/pages/board/market_board_page.dart | 15 ++++++++++-- lib/views/pages/board/market_detail_page.dart | 24 ++++++++++++++----- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/apis/apis.dart b/lib/apis/apis.dart index 782e078d..62e65fba 100644 --- a/lib/apis/apis.dart +++ b/lib/apis/apis.dart @@ -1487,6 +1487,7 @@ class APIs { ); if (response.statusCode == 200) { + print(json.decode(utf8.decode(response.bodyBytes))); final responseData = json.decode(utf8.decode(response.bodyBytes)); final data = responseData['data']; if (data != null && data is List) { @@ -2001,6 +2002,7 @@ class APIs { ); if (response.statusCode == 200) { + print(json.decode(utf8.decode(response.bodyBytes))); List body = json.decode(utf8.decode(response.bodyBytes))['data']; return body.map((dynamic item) => MarketBoard.fromJson(item)).toList(); } else { diff --git a/lib/views/pages/board/market_board_page.dart b/lib/views/pages/board/market_board_page.dart index ccbda6ef..9d0306c9 100644 --- a/lib/views/pages/board/market_board_page.dart +++ b/lib/views/pages/board/market_board_page.dart @@ -25,6 +25,7 @@ class MarketBoardPage extends StatefulWidget { + @override State createState() => _MarketBoardPageState(); } @@ -32,6 +33,8 @@ class MarketBoardPage extends StatefulWidget { class _MarketBoardPageState extends State { bool isDrawerStart = false; List marketBoardList = []; + //String createdAt = ''; + void initState() { @@ -42,8 +45,13 @@ class _MarketBoardPageState extends State { Future _fetchMarketArticles() async { try { var fetchedData = await APIs.getMarketArticles(); // API 호출 함수 호출 + print(fetchedData); setState(() { marketBoardList = fetchedData; // 불러온 데이터를 리스트에 할당 + for (var marketBoard in marketBoardList) { + print('createdAt: ${marketBoard.createdAt}'); + } + }); } catch (error) { // 에러 처리 @@ -54,6 +62,7 @@ class _MarketBoardPageState extends State { @override Widget build(BuildContext context) { + final double screenWidth = MediaQuery.of(context).size.height; final bool isSmallScreen = screenWidth <= 700; return Scaffold( @@ -253,8 +262,10 @@ class _MarketBoardPageState extends State { mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - '${widget.marketBoard?.createdAt}', - // DataUtils.getTime(widget.marketBoard?.createdAt), // 생성 날짜 정보 사용 + //DataUtils.getTime(widget.marketBoard?.createdAt),//formatexception : invalid date format null 에러남 + '${widget.marketBoard?.createdAt.toString()}', //그냥 null 반환 + // DataUtils.getTime(widget.marketBoard!.createdAt), //null check operator used on a null vlaue 에러 + //DataUtils.getTime(widget.marketBoard?.createdAt.toString()), //걍 빨간줄 style: TextStyle( color: Color(0xffC1C1C1), fontSize: 12.spMin, diff --git a/lib/views/pages/board/market_detail_page.dart b/lib/views/pages/board/market_detail_page.dart index df5b48f2..ab6c915a 100644 --- a/lib/views/pages/board/market_detail_page.dart +++ b/lib/views/pages/board/market_detail_page.dart @@ -75,6 +75,8 @@ class _MarketDetailPageState extends State { @override Widget build(BuildContext context) { + //print('Data from marketBoard: ${widget.marketBoard.createdAt}'); + final double screenWidth = MediaQuery.of(context).size.height; final bool isSmallScreen = screenWidth <= 700; @@ -85,6 +87,14 @@ class _MarketDetailPageState extends State { final marketcommentProvider = Provider.of(context, listen: false); marketcommentProvider.getMarketComments(widget.marketBoard.articleId!); + bool showLoading = marketcommentProvider.loading; + if (showLoading) { + Future.delayed(Duration(seconds: 3), () { + setState(() { + showLoading = false; + }); + }); + } return GestureDetector( onTap: (){ @@ -345,13 +355,15 @@ class _MarketDetailPageState extends State { ), Divider(thickness: 1.2.h,color: Color(0xffE5EBFF),), + //댓글 - marketcommentProvider.loading? - Container( - alignment: Alignment.center, - child: Image( - image: AssetImage( - "assets/illustration/loading_01.gif"))) + showLoading + ? Container( + alignment: Alignment.center, + child: Image( + image: AssetImage("assets/illustration/loading_01.gif"), + ), + ) : Column( children: [ From f48ba05b98f57448f0652400733c77c6e2607a1d Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Tue, 5 Sep 2023 16:42:55 +0900 Subject: [PATCH 08/10] =?UTF-8?q?createdAt=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/views/pages/board/market_board_page.dart | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/views/pages/board/market_board_page.dart b/lib/views/pages/board/market_board_page.dart index 9d0306c9..8ba34025 100644 --- a/lib/views/pages/board/market_board_page.dart +++ b/lib/views/pages/board/market_board_page.dart @@ -262,10 +262,7 @@ class _MarketBoardPageState extends State { mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - //DataUtils.getTime(widget.marketBoard?.createdAt),//formatexception : invalid date format null 에러남 - '${widget.marketBoard?.createdAt.toString()}', //그냥 null 반환 - // DataUtils.getTime(widget.marketBoard!.createdAt), //null check operator used on a null vlaue 에러 - //DataUtils.getTime(widget.marketBoard?.createdAt.toString()), //걍 빨간줄 + DataUtils.getTime(marketBoard.createdAt), style: TextStyle( color: Color(0xffC1C1C1), fontSize: 12.spMin, From 98779113bd4394591e04ec73fa65a013523efd68 Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Tue, 5 Sep 2023 17:20:25 +0900 Subject: [PATCH 09/10] =?UTF-8?q?=EC=83=81=EC=84=B8=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=EC=98=A4=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/apis/apis.dart | 40 +++++++++++++++++++ .../components/total_article_widget.dart | 5 +-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/lib/apis/apis.dart b/lib/apis/apis.dart index fb5426d7..a12976d2 100644 --- a/lib/apis/apis.dart +++ b/lib/apis/apis.dart @@ -1529,6 +1529,46 @@ class APIs { } } + + /*장터 게시판 게시글 상세 조회*/ + static Future getMarketArticle(int articleId) async { + final _url = 'http://3.34.2.246:8080/api/v2/market-articles/${articleId}'; + + //토큰 읽어오기 + var jwtToken = await storage.read(key: 'token'); + jwtToken = json.decode(jwtToken!)['data']['accessToken']; + + final response = await http.get( + Uri.parse(_url), + headers: { + 'Authorization': 'Bearer $jwtToken', + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode == 200) { + print(json.decode(utf8.decode(response.bodyBytes))); + dynamic body = json.decode( + utf8.decode(response.bodyBytes))['data']; + return MarketBoard.fromJson(body); + + + //fail + } else { + print(json.decode(utf8.decode(response.bodyBytes))); + if(json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-002'){ + print('액세스 토큰 만료'); + throw 'AT-C-002'; + } else if(json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-007'){ + print('로그아웃된 토큰'); + throw 'AT-C-007'; + }else{ + + } + throw Exception('요청 오류'); + } + } + /*상품 판매글 검색*/ static Future> marketSearch(String keyword) async { try { diff --git a/lib/views/components/total_article_widget.dart b/lib/views/components/total_article_widget.dart index b6e1ba88..7c3143ca 100644 --- a/lib/views/components/total_article_widget.dart +++ b/lib/views/components/total_article_widget.dart @@ -267,11 +267,11 @@ class _TotalArticleWidgetState extends State{ image: AssetImage( "assets/illustration/loading_01.gif"))); } else{ - MarketArticle data = snapshot.data; + MarketBoard data = snapshot.data; //받아온 후 WidgetsBinding.instance!.addPostFrameCallback((_) {Navigator.push( context, - MaterialPageRoute(builder: (context) => MarketDetailPage(screenArguments: widget.screenArguments)), + MaterialPageRoute(builder: (context) => MarketDetailPage(screenArguments: widget.screenArguments, marketBoard: data,)), ); }); return Container( @@ -293,4 +293,3 @@ class _TotalArticleWidgetState extends State{ ); } } - From 1160ed5f9729301e59bc97bf25d6545dd644b1f5 Mon Sep 17 00:00:00 2001 From: KIM-JUHYEON-79 Date: Tue, 5 Sep 2023 17:28:37 +0900 Subject: [PATCH 10/10] =?UTF-8?q?=EC=9E=A5=ED=84=B0=20=EC=A0=84=EB=B6=80?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EB=A8=B8=EC=A7=80=20=EC=98=A4=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/apis/apis.dart | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/apis/apis.dart b/lib/apis/apis.dart index a12976d2..5d37fc4a 100644 --- a/lib/apis/apis.dart +++ b/lib/apis/apis.dart @@ -1418,12 +1418,11 @@ class APIs { /*전체게시판 글 전부 조회*/ static Future> TotalArticles() async { - final _url = 'https://aaa1f771-6012-440a-9939-4328d9519a52.mock.pstmn.io/api/v2/articles'; + final _url = 'http://3.34.2.246:8080/api/v2/articles'; //토큰 읽어오기 var jwtToken = await storage.read(key: 'token'); jwtToken = json.decode(jwtToken!)['data']['accessToken']; - final response = await http.get( Uri.parse(_url), headers: { @@ -1431,26 +1430,21 @@ class APIs { 'Content-Type': 'application/json', }, ); - if (response.statusCode == 200) { print(json.decode(utf8.decode(response.bodyBytes))); List body = json.decode( utf8.decode(response.bodyBytes))['data']; return body.map((dynamic item) => Board.fromJson(item)).toList(); - - //fail } else { print(json.decode(utf8.decode(response.bodyBytes))); - if (json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-002') { + if(json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-002'){ print('액세스 토큰 만료'); throw 'AT-C-002'; - } else - if (json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-007') { + } else if(json.decode(utf8.decode(response.bodyBytes))['code'] == 'AT-C-007'){ print('로그아웃된 토큰'); throw 'AT-C-007'; - } else { - + }else{ } throw Exception('요청 오류'); }