Skip to content

Commit

Permalink
Merge pull request #118 from tukcomCD2024/feat/#115-backend-bookmark-…
Browse files Browse the repository at this point in the history
…detail

Feat/#115 Bookmark Detail
  • Loading branch information
yeonjy authored May 15, 2024
2 parents 7ac88e2 + e2b07ca commit a8e2e7d
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 26 deletions.
4 changes: 2 additions & 2 deletions backend/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'

testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
testAnnotationProcessor "org.mapstruct:mapstruct-processor:1.5.5.Final"
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}

tasks.named('bootBuildImage') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.rollthedice.backend.domain.bookmark.api;

import com.rollthedice.backend.domain.bookmark.dto.response.BookmarkResponse;
import com.rollthedice.backend.domain.news.dto.response.NewsResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand All @@ -12,24 +13,40 @@

public interface BookmarkApi {
@Operation(
summary = "북마크 조회",
summary = "북마크 전체 조회",
description = "회원이 북마크한 뉴스를 페이지로 나누어 조회합니다.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"bookmark"}
tags = {"북마크"}
)
@ApiResponse(
responseCode = "200",
description = "OK"
)
List<NewsResponse> getBookmarked(
List<NewsResponse> getAllBookmarkedNews(
Pageable pageable
);

@Operation(
summary = "뉴스 북마크 여부 조회",
description = "로그인한 회원이 해당 뉴스를 북마크 했는지 여부를 조회합니다.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"북마크"}
)
@ApiResponse(
responseCode = "200",
description = "OK"
)
BookmarkResponse getIsBookmarked(
@Parameter(in = ParameterIn.PATH, description = "뉴스 ID", required = true)
Long newsId
);


@Operation(
summary = "북마크 저장",
description = "뉴스에 대하여 북마크로 저장합니다.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"bookmark"}
tags = {"북마크"}
)
@ApiResponse(
responseCode = "201",
Expand All @@ -44,7 +61,7 @@ void saveBookmark(
summary = "북마크 삭제",
description = "저장된 북마크를 해제합니다.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"bookmark"}
tags = {"북마크"}
)
@ApiResponse(
responseCode = "204",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.rollthedice.backend.domain.bookmark.api;

import com.rollthedice.backend.domain.bookmark.dto.response.BookmarkResponse;
import com.rollthedice.backend.domain.bookmark.service.BookmarkService;
import com.rollthedice.backend.domain.news.dto.response.NewsResponse;
import lombok.RequiredArgsConstructor;
Expand All @@ -18,8 +19,15 @@ public class BookmarkController implements BookmarkApi {
@ResponseStatus(HttpStatus.OK)
@GetMapping("")
@Override
public List<NewsResponse> getBookmarked(final Pageable pageable) {
return bookmarkService.getBookmarkedNews(pageable);
public List<NewsResponse> getAllBookmarkedNews(final Pageable pageable) {
return bookmarkService.getAllBookmarkedNews(pageable);
}

@ResponseStatus(HttpStatus.OK)
@GetMapping("/{newsId}")
@Override
public BookmarkResponse getIsBookmarked(@PathVariable final Long newsId) {
return bookmarkService.getIsBookmarked(newsId);
}

@ResponseStatus(HttpStatus.CREATED)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.rollthedice.backend.domain.bookmark.dto.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BookmarkResponse {
private Long id;
private Boolean isBookmarked;

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@Repository
public interface BookmarkRepository extends JpaRepository<Bookmark, Long> {
Boolean existsBookmarkByMemberAndNews(Member member, News news);
Boolean existsBookmarkByMemberAndNewsId(Member member, Long newsId);

List<Bookmark> findAllByMemberOrderByCreatedAt(Member member, Pageable pageable);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.rollthedice.backend.domain.bookmark.service;

import com.rollthedice.backend.domain.bookmark.dto.response.BookmarkResponse;
import com.rollthedice.backend.domain.bookmark.entity.Bookmark;
import com.rollthedice.backend.domain.bookmark.repository.BookmarkRepository;
import com.rollthedice.backend.domain.member.entity.Member;
Expand All @@ -11,14 +12,15 @@
import com.rollthedice.backend.domain.news.repository.NewsRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
@RequiredArgsConstructor
public class BookmarkService {
private final AuthService authService;
private final BookmarkRepository bookmarkRepository;
Expand All @@ -31,7 +33,7 @@ public boolean isBookmarked(Member member, News news) {
}

@Transactional(readOnly = true)
public List<NewsResponse> getBookmarkedNews(Pageable pageable) {
public List<NewsResponse> getAllBookmarkedNews(Pageable pageable) {
Member member = authService.getMember();
return bookmarkRepository.findAllByMemberOrderByCreatedAt(member, pageable).stream()
.map(bookmark -> newsMapper.toResponse(bookmark.getNews(), true))
Expand All @@ -53,5 +55,14 @@ public void saveBookmark(Long newsId) {
public void deleteBookmark(Long newsId) {
bookmarkRepository.deleteByNewsId(newsId);
}

public BookmarkResponse getIsBookmarked(Long newsId) {
Member member = authService.getMember();
Boolean isBookmarked = bookmarkRepository.existsBookmarkByMemberAndNewsId(member, newsId);
return BookmarkResponse.builder()
.id(newsId)
.isBookmarked(isBookmarked)
.build();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public OpenAPI openAPI() {

private List<Server> getServers() {
return List.of(new Server()
.url("/api")
.description("백엔드 api 서버")
);
}
Expand Down
16 changes: 16 additions & 0 deletions iOS/RollTheDice/RollTheDice.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
6C3237B72B7C434600B699AB /* ChatType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C3237B62B7C434600B699AB /* ChatType.swift */; };
6C41B8D22BDE696200274FA4 /* NewsType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C41B8D12BDE696200274FA4 /* NewsType.swift */; };
6C41B8D42BDE6D2500274FA4 /* TypePieChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C41B8D32BDE6D2500274FA4 /* TypePieChartView.swift */; };
6C41B8DA2BE104A800274FA4 /* RecentNewsCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C41B8D92BE104A800274FA4 /* RecentNewsCardView.swift */; };
6C41B8DC2BE1095800274FA4 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C41B8DB2BE1095800274FA4 /* ChatListView.swift */; };
6C454A782B9DA657006FD9D0 /* SignUpQuestionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C454A772B9DA657006FD9D0 /* SignUpQuestionView.swift */; };
6C454A7A2B9DA67C006FD9D0 /* SignUpViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C454A792B9DA67C006FD9D0 /* SignUpViewModel.swift */; };
6C454A7C2B9DA71C006FD9D0 /* SignUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C454A7B2B9DA71C006FD9D0 /* SignUpView.swift */; };
Expand Down Expand Up @@ -97,6 +99,8 @@
6C3237B62B7C434600B699AB /* ChatType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatType.swift; sourceTree = "<group>"; };
6C41B8D12BDE696200274FA4 /* NewsType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsType.swift; sourceTree = "<group>"; };
6C41B8D32BDE6D2500274FA4 /* TypePieChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypePieChartView.swift; sourceTree = "<group>"; };
6C41B8D92BE104A800274FA4 /* RecentNewsCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentNewsCardView.swift; sourceTree = "<group>"; };
6C41B8DB2BE1095800274FA4 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = "<group>"; };
6C454A772B9DA657006FD9D0 /* SignUpQuestionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpQuestionView.swift; sourceTree = "<group>"; };
6C454A792B9DA67C006FD9D0 /* SignUpViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewModel.swift; sourceTree = "<group>"; };
6C454A7B2B9DA71C006FD9D0 /* SignUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -218,6 +222,15 @@
path = Report;
sourceTree = "<group>";
};
6C41B8D62BE1048500274FA4 /* ChatList */ = {
isa = PBXGroup;
children = (
6C41B8D92BE104A800274FA4 /* RecentNewsCardView.swift */,
6C41B8DB2BE1095800274FA4 /* ChatListView.swift */,
);
path = ChatList;
sourceTree = "<group>";
};
6C454A762B9DA62C006FD9D0 /* SignUp */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -324,6 +337,7 @@
6C7704902B7229B6001B17CB /* Debate */ = {
isa = PBXGroup;
children = (
6C41B8D62BE1048500274FA4 /* ChatList */,
6CE103182BD57A1600498AA4 /* Summary */,
6CDB29F72BAA06FB0081037B /* ChatGPT */,
6C3237B32B7C433000B699AB /* ChatType */,
Expand Down Expand Up @@ -652,6 +666,7 @@
6CDB29FF2BAA08280081037B /* GPTChatListViewModel.swift in Sources */,
6CF130AD2BAB0C4400A437B6 /* AuthenticationViewModel.swift in Sources */,
6CDB29F92BAA07350081037B /* GPTChat.swift in Sources */,
6C41B8DC2BE1095800274FA4 /* ChatListView.swift in Sources */,
6CDB29FD2BAA07FD0081037B /* GPTChatView.swift in Sources */,
6C41B8D22BDE696200274FA4 /* NewsType.swift in Sources */,
357666102BBD4BF6002C226A /* ReportListView.swift in Sources */,
Expand Down Expand Up @@ -689,6 +704,7 @@
6C77048C2B722686001B17CB /* MainTabView.swift in Sources */,
6C7704992B722A20001B17CB /* MainTabViewModel.swift in Sources */,
6C454A7C2B9DA71C006FD9D0 /* SignUpView.swift in Sources */,
6C41B8DA2BE104A800274FA4 /* RecentNewsCardView.swift in Sources */,
6CF130C72BAB7B9800A437B6 /* RollTheDiceAPINews.swift in Sources */,
6CE1031A2BD57A2500498AA4 /* DebateSummaryView.swift in Sources */,
6CE1030C2BD56A4000498AA4 /* TypeReportView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//
// ChatListView.swift
// RollTheDice
//
// Created by Subeen on 4/30/24.
//

import SwiftUI

struct ChatListView: View {

@EnvironmentObject var pathModel: PathModel

var body: some View {
ZStack {
Color.backgroundDark.ignoresSafeArea(.all)
ScrollView {
VStack(alignment: .leading, spacing: 44) {
recentNewsView
debateChatListView
}
.padding(.horizontal, 120)
}
.scrollIndicators(.hidden)
}
}

@ViewBuilder
var recentNewsView: some View {
VStack(alignment: .leading) {
Text("최근 본 뉴스")
.foregroundStyle(.basicWhite)
.font(.pretendardBold32)
HStack {
RecentNewsCardView()
Spacer()
RecentNewsCardView()
Spacer()
RecentNewsCardView()
}
}
}

@ViewBuilder
var debateChatListView: some View {
VStack(alignment: .leading, spacing: 26) {
Text("채팅방")
.foregroundStyle(.basicWhite)
.font(.pretendardBold32)
debateChatCellView
debateChatCellView
debateChatCellView
}
}

var debateChatCellView: some View {
HStack {
HStack(alignment: .center, spacing: 16) {
Text("🏛️")
.padding(.leading, 26)
.font(.pretendardBold32)
Text("경제 기사 경제 기사저제목목제목 제목")
.foregroundStyle(.gray07)
.font(.pretendardBold24)
.padding(.vertical, 24)

Spacer()
Image(.chevronRight)
}
.background(.gray01)
.clipShape(RoundedRectangle(cornerRadius: 8))
.padding(.trailing, 16)

//TODO: 버튼 영역 수정하기
Button {
pathModel.paths.append(.debateSummaryView)
} label: {
Image(.chevronLeft)
// .background(.gray01)

}
.frame(width: 80, height: 80)
.background(.gray01)
.clipShape(RoundedRectangle(cornerRadius: 8))
}
}
}

#Preview {
ChatListView()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// RecentNewsCardView.swift
// RollTheDice
//
// Created by Subeen on 4/30/24.
//

import SwiftUI

struct RecentNewsCardView: View {
var body: some View {
HStack {
titleView
}
// .frame(width: 260, height: 244)
.clipShape(RoundedRectangle(cornerRadius: 8))
}

var titleView: some View {
ZStack {
VStack(alignment: .center, spacing: 20) {
Image(.chevronLeft)
Text("제목ahrhrhra제목 제목 미젝ㅁㄱㅈ 메좀ㄱㅈ게조깆거ㅣㅓ린러.ㄴ릴")
.multilineTextAlignment(.center)
.foregroundStyle(.gray07)
.font(.pretendardBold24)
.frame(width: 240, height: 96)
.padding(.horizontal, 10)
.padding(.vertical, 30)
.background(.gray01)
.clipShape(RoundedRectangle(cornerRadius: 2))
.overlay {
RoundedRectangle(cornerRadius: 2)
.stroke(Color.gray05, lineWidth: 1.0)
}
.shadow(color: .basicBlack.opacity(0.1), radius: 2)
Button {

} label: {
Text("토론 시작하기")
.foregroundStyle(.basicWhite)
.font(.pretendardRegular14)
.padding(.horizontal, 38)
.padding(.vertical, 10)
.background(.primary01)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
}
}
.padding(.horizontal, 20)
.padding(.top, 24)
.padding(.bottom, 32)
.background(.gray02)
}
}

#Preview {
RecentNewsCardView()
}
Loading

0 comments on commit a8e2e7d

Please sign in to comment.