Skip to content

Commit

Permalink
Merge pull request #51 from SproutMJ/develop
Browse files Browse the repository at this point in the history
수정사항 적용
  • Loading branch information
SproutMJ authored May 29, 2024
2 parents eb01433 + 5b3f94d commit 0b34914
Show file tree
Hide file tree
Showing 14 changed files with 292 additions and 34 deletions.
1 change: 1 addition & 0 deletions backend/src/main/java/hello/aimju/Board/domain/Board.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class Board {
private Long id;
private String title;
private LocalDate createdTime = LocalDate.now();
@Column(columnDefinition = "TEXT")
private String content;
@OneToMany(mappedBy = "board",cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package hello.aimju.Board.repository;

import hello.aimju.Board.domain.Board;
import hello.aimju.recipe.domain.Recipe;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -12,4 +11,8 @@ public interface BoardRepository extends JpaRepository<Board, Long> {
List<Board> findAllByUserId(Long userId);

Page<Board> findByTitleContaining(String searchKeyword, Pageable pageable);

Page<Board> findByUserIdAndTitleContaining(Long userId, String searchKeyword, Pageable pageable);

Page<Board> findAllByUserId(Long userId, Pageable pageable);
}
36 changes: 36 additions & 0 deletions backend/src/main/java/hello/aimju/Board/service/BoardService.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,42 @@ public ResponseEntity<RetrieveBoardListResponseDto> retrieveSearchBoard(int pag
return ResponseEntity.ok().body(new RetrieveBoardListResponseDto((long) boardLists.getTotalPages(), getBoardLists));
}

public ResponseEntity<RetrieveBoardListResponseDto> retrieveCurrentUserBoard(int page, int size, HttpSession session) {
Pageable pageable;
pageable = PageRequest.of(page, size, Sort.by("id").descending());
User user = getUserFromSession(session);
Page<Board> boardLists = boardRepository.findAllByUserId(user.getId(), pageable);
List<RetrieveBoardResponseDto> getBoardLists = boardLists.stream()
.map(tmp -> RetrieveBoardResponseDto.builder()
.id(tmp.getId())
.title(tmp.getTitle())
.createdTime(tmp.getCreatedTime())
.commentNum((long) tmp.getComments().size())
.username(tmp.getUser().getUserName())
.build())
.collect(Collectors.toList());

return ResponseEntity.ok().body(new RetrieveBoardListResponseDto((long) boardLists.getTotalPages(), getBoardLists));
}

public ResponseEntity<RetrieveBoardListResponseDto> retrieveCurrentUserSearchBoard(int page, int size, HttpSession session, String searchKeyword) {
Pageable pageable;
pageable = PageRequest.of(page, size, Sort.by("id").descending());
User user = getUserFromSession(session);
Page<Board> boardLists = boardRepository.findByUserIdAndTitleContaining(user.getId(), searchKeyword, pageable);
List<RetrieveBoardResponseDto> getBoardLists = boardLists.stream()
.map(tmp -> RetrieveBoardResponseDto.builder()
.id(tmp.getId())
.title(tmp.getTitle())
.createdTime(tmp.getCreatedTime())
.commentNum((long) tmp.getComments().size())
.username(tmp.getUser().getUserName())
.build())
.collect(Collectors.toList());

return ResponseEntity.ok().body(new RetrieveBoardListResponseDto((long) boardLists.getTotalPages(), getBoardLists));
}

public ResponseEntity<?> retrieveOneBoard(Long id) {
Board findBoard = boardRepository.findById(id).get();
RetrieveOneBoardResponseDto board = RetrieveOneBoardResponseDto.builder()
Expand Down
11 changes: 11 additions & 0 deletions backend/src/main/java/hello/aimju/controller/BoardController.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ public ResponseEntity<?> retrieve(@RequestParam(name = "page", defaultValue = "0
return boardService.retrieveSearchBoard(page, size,searchKeyword);
}
}
@GetMapping("/current-user")
public ResponseEntity<?> retrieveCurrentUser(@RequestParam(name = "page", defaultValue = "0") int page,
@RequestParam(name = "size", defaultValue = "5") int size,
@RequestParam(name = "searchKeyword", required = false) String searchKeyword,
HttpSession session){
if (searchKeyword == null) {
return boardService.retrieveCurrentUserBoard(page, size, session);
}else{
return boardService.retrieveCurrentUserSearchBoard(page, size, session, searchKeyword);
}
}

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<?> retrieveOneBoard(@PathVariable("id") Long id){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public List<GetAllRecipesResponseDto> getRecipes(HttpSession session) {
}

@RequestMapping(value = "/recipe/{recipeId}", method = RequestMethod.GET)
public GetRecipeResponseDto getRecipeDetails(@PathVariable("recipeId") Long recipeId) {
GetRecipeResponseDto recipeDetails = recipeService.getRecipeDetails(recipeId);
public GetRecipeResponseDto getRecipeDetails(@PathVariable("recipeId") Long recipeId ,HttpSession session) {
GetRecipeResponseDto recipeDetails = recipeService.getRecipeDetails(recipeId, session);
return recipeDetails;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,13 @@ public List<GetAllRecipesResponseDto> getAllRecipes(HttpSession session) {
return responseDtoList;
}

public GetRecipeResponseDto getRecipeDetails(Long recipeId) {
public GetRecipeResponseDto getRecipeDetails(Long recipeId, HttpSession session) {
User user = getUserFromSession(session);
Recipe recipe = recipeRepository.findById(recipeId)
.orElseThrow(() -> new IllegalArgumentException("레시피를 찾을 수 없습니다. ID: " + recipeId));

if (!Objects.equals(user.getId(), recipe.getUser().getId())){
throw new IllegalArgumentException("접근 권한이 없습니다");
}
GetRecipeResponseDto responseDto = new GetRecipeResponseDto();
responseDto.setRecipeId(recipeId);
responseDto.setMenu(recipe.getMenu());
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/app/boards/[boardId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,7 @@ export default function BoardDetail({params}: {params: {boardId: string}}) {
<h2 className="text-2xl font-bold text-gray-900 dark:text-gray-100 mb-2">
{title}
</h2>
<p className="text-gray-700 dark:text-gray-400">
{content}
</p>
<div dangerouslySetInnerHTML={{__html: content.replace(/\n/g, '<br/>')}}/>
</div>
<hr className="mb-1"/>
<div className="mb-4">
Expand Down
69 changes: 58 additions & 11 deletions frontend/src/app/boards/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ To read more about using these font, please visit the Next.js documentation:
'use client'
import { Button } from "@/components/ui/button"
import Link from "next/link"
import { CardTitle, CardDescription, CardHeader, CardContent, CardFooter, Card } from "@/components/ui/card"
import { CardTitle, CardDescription, CardHeader, CardFooter, Card } from "@/components/ui/card"
import {Header} from "@/components/ui/header";
import React, {useEffect, useState} from "react";
import axios from "axios";
import useUserStore from "@/store/useUserStore";
import useBoardStore from '@/store/useBoardStore';

type Board = {
id: number;
Expand All @@ -40,6 +41,7 @@ export default function Board() {
const [searchKeyword, setSearchKeyword] = useState(null);
const [boards, setBoards] = useState<Board[]>([]);
const {getState} = useUserStore;
const ownBoard = useBoardStore((state) => state.ownBoard);

const getBoards = async (page = 0, searchKeyword = null)=>{
try {
Expand Down Expand Up @@ -74,18 +76,63 @@ export default function Board() {
}
};

useEffect(()=>{
getBoards();
}, []);
const getOwnBoards = async (page = 0, searchKeyword = null) => {
try {
let response;
if (searchKeyword === null) {
response = await axios.get('/api/boards/current-user', {
params: {
page: page,
}
});
} else {
response = await axios.get('/api/boards/current-user', {
params: {
page: page,
searchKeyword: searchKeyword
}
});
}

const boards: Board[] = await response.data.boardLists.map((b: any) => ({
id: b.id,
title: b.title,
commentNum: b.commentNum,
createdTime: b.createdTime,
username: b.username,
}));
setTotalPages((response?.data.totalPages === 0 ? 0 : response?.data.totalPages - 1));
setBoards(boards);
setSearchKeyword(searchKeyword);
} catch (error) {
console.log(error)
}
};

const handlePrevPage = ()=> {
getBoards(currentPage-1, searchKeyword);
setCurrentPage(currentPage-1);
useEffect(() => {
if (ownBoard === 1) {
getOwnBoards();
} else {
getBoards();
}
}, [ownBoard]);

const handlePrevPage = () => {
if (ownBoard === 1) {
getOwnBoards(currentPage - 1, searchKeyword);
} else {
getBoards(currentPage - 1, searchKeyword);
}
setCurrentPage(currentPage - 1);
}

const handleNextPage = ()=> {
getBoards(currentPage+1, searchKeyword);
setCurrentPage(currentPage+1);
const handleNextPage = () => {
if (ownBoard === 1) {
getOwnBoards(currentPage + 1, searchKeyword);
} else {
getBoards(currentPage + 1, searchKeyword);
}
setCurrentPage(currentPage + 1);
}

return (
Expand Down Expand Up @@ -122,7 +169,7 @@ export default function Board() {
</div>

<div className="fixed bottom-6 right-6">
<Link href={'/boards/writing'}>
<Link href={'/boards/writing/0'}>
<Button size="lg">
<PlusIcon className="h-6 w-6" />
<span className="sr-only">Add new</span>
Expand Down
110 changes: 110 additions & 0 deletions frontend/src/app/boards/writing/[recipeId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
'use client'
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Header } from '@/components/ui/header';
import { Textarea } from '@/components/ui/textarea';
import { useRouter } from 'next/navigation';

export default function PostWriting({ params }: { params: { recipeId: number } }) {
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const router = useRouter();
const [recipes, setRecipes] = useState<{ recipeId: number; menu: string; }[]>([]);
const [selectedRecipe, setSelectedRecipe] = useState<number | null>(null); // 선택된 레시피 ID

useEffect(() => {
if (params.recipeId !== 0) {
const fetchRecipeContent = async () => {
try {
const response = await axios.get(`/api/recipe/${params.recipeId}`);
setTitle(response.data.menu);
setContent(`재료: ${response.data.ingredients.join(', ')}\n레시피:\n${response.data.recipeInfoList.map((info: string, index:number) => `${index + 1}. ${info}`).join('\n')}`);
} catch (error) {
console.error("Error fetching recipe content:", error);
}
};
fetchRecipes();
fetchRecipeContent();
} else {
setTitle('제목을 입력해주세요');
setContent('내용을 입력해주세요');
}
}, [params.recipeId]);

const handleBoardSave = async () => {
try {
const response = await axios.post('/api/boards', {
title: title,
content: content,
});
router.push('/boards');
} catch (error) {
console.error("Error saving board:", error);
}
};

const fetchRecipes = async () => {
try {
const response = await axios.get('/api/recipes');
setRecipes(response.data);
} catch (error) {
console.error("Error fetching recipes:", error);
}
};

const handleRecipeSelection = (recipeId: number) => {
setSelectedRecipe(recipeId);
};

const handleRoutingBoards = (recipeId: number) => {
router.push(`/boards/writing/${recipeId}`);
};

return (
<>
<Header />
<main className="py-8 h-[calc(100vh-72px)]">
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 gap-6">
<div>
<label className="block mb-2 font-bold text-2xl text-white">제목</label>
<Input value={title} onChange={(e) => setTitle(e.target.value)} />
</div>
<div>
<label className="block mb-2 font-bold text-2xl text-white">레시피 가져오기</label>
<select
className="w-full p-2 rounded border border-gray-300 focus:outline-none focus:border-indigo-500 bg-gray-300 text-black"
value={selectedRecipe || ''}
onChange={(e) => {
const selectedRecipeId = Number(e.target.value);
handleRecipeSelection(selectedRecipeId);
handleRoutingBoards(selectedRecipeId);
}}
>
<option value="">레시피 선택</option>
{recipes.map(recipe => (
<option key={recipe.recipeId} value={recipe.recipeId}>{recipe.menu}</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-bold text-2xl text-white">내용</label>
<Textarea
className="w-full h-full resize-none"
style={{minHeight: '200px', maxHeight: '60vh'}}
value={content}
onChange={(e) => setContent(e.target.value)}
/>
</div>
<div className="flex justify-center mt-6">
<Button onClick={() => router.push('/boards')} variant="outline">취소</Button>
<Button onClick={handleBoardSave}>저장</Button>
</div>
</div>
</div>
</main>
</>
)
}
Loading

0 comments on commit 0b34914

Please sign in to comment.