Skip to content

Commit

Permalink
Merge branch 'master' into postdetailapi
Browse files Browse the repository at this point in the history
  • Loading branch information
ymj07168 authored Oct 24, 2024
2 parents 7bd77ba + d46f091 commit 69aab9d
Show file tree
Hide file tree
Showing 18 changed files with 646 additions and 356 deletions.
36 changes: 36 additions & 0 deletions src/api/detail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import client from "./client";
import { getCookie } from "./cookie";

const token = getCookie('accessToken');

// TIL 글 상세 조회
export const getTILDetail = async ({ tilId }) => {
console.log(tilId);
return await client.get(`/api/tils/${tilId}`);
};

// TIL 글 작성 조회
export const postTIL = async (tilData) => {
return await client.post(`/api/til`, tilData, {
headers: {
Authorization: `Bearer ${token}`,
},
});
};

// TIL 글 알고리즘 조회
export const getAlgorithms = async () => {
return await client.get(`/api/algorithms`);
};

// TIL 글 수정 조회
export const putTIL = async ({ tilId }) => {
console.log(tilId);
return await client.put(`/api/tils/${tilId}`);
};

// TIL 글 삭제 조회
export const deleteTIL = async ({ tilId }) => {
console.log(tilId);
return await client.delete(`/api/tils/${tilId}`);
};
19 changes: 18 additions & 1 deletion src/api/main.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
// import client from "./client";
import client from "./client";
import { getCookie } from "./cookie";

const token = getCookie("accessToken");

// TIL 글 목록 조회
export const getTIL = async ({ pageNumber }) => {
return await client.get(`/api/tils?page=${pageNumber}`);
return await client.get(`/api/tils?page=${pageNumber}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
};

// 챌린지 목록 조회
export const getChallenges = async ({ pageSize }) => {
return await client.get(`/api/challenges?page=${pageSize}`);
};

// TIL 글 상세 조회
export const getTILDetail = async ({ tilId }) => {
console.log(tilId);
return await client.get(`/api/tils/${tilId}`);
};

// 챌린지 상세 문제 조회
export const getChallengeDetail = async ({ challengeId }) => {
return await client.get(`/api/challenges/${challengeId}`);
};
31 changes: 31 additions & 0 deletions src/api/mypage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import client from "./client";
import { getCookie } from "./cookie";

const token = getCookie("accessToken");

// 내 글 목록 조회
export const getMyTILs = async ({ pageSize }) => {
return await client.get(`/api/mypage/tils?page=${pageSize}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
};

// 좋아요 글 목록 조회
export const getLikeTILs = async ({ pageSize }) => {
return await client.get(`/api/mypage/likes?page=${pageSize}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
};

// 통계 조회
export const getStatistics = async ({ pageSize }) => {
return await client.get(`/api/mypage/statistics`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
};
17 changes: 3 additions & 14 deletions src/assets/Arrow down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions src/components/EditorPage/Dropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import { ReactSVG } from "react-svg";
import Arrowdown from "../../assets/Arrow down.svg";

const Dropdown = ({ name = null, value, options, placeholder, onChange }) => {
return (
<div className="relative w-full">
<select
value={name === "algorithm" ? options[value] : value}
className="w-full px-4 py-2 text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-1 focus:ring-orange-200"
onChange={onChange}
>
<option value="" disabled selected hidden>
{placeholder}
</option>
{options.map((option, index) => (
<option key={index} value={name === "algorithm" ? index + 1 : option}>
{option}
</option>
))}
</select>
<div className="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none">
<ReactSVG src={Arrowdown} />
</div>
</div>
);
};

export default Dropdown;
26 changes: 18 additions & 8 deletions src/components/EditorPage/EditorFooter.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { Button } from "@mui/material";
import React from "react";
import { useNavigate } from "react-router-dom";

function EditorFooter() {
function EditorFooter({ handlePostData }) {
const navigate = useNavigate();

const handleGoBack = () => {
Expand All @@ -10,22 +11,31 @@ function EditorFooter() {

return (
<div className="flex items-center justify-between py-1.5 px-2 editor-footer">
<button
<Button variant="text" color="inherit" onClick={handleGoBack}>
나가기
</Button>
{/* <button
className="flex items-center px-2 py-2 font-bold text-gray-400 duration-200 rounded-xl hover:bg-red-500 hover:text-white"
onClick={handleGoBack}
>
나가기
</button>
</button> */}
<div className="flex space-x-2">
<button className="px-4 py-2 font-bold text-green-400 duration-150 rounded hover:text-green-600">
<Button variant="text" color="info">
임시저장
</Button>
<Button variant="contained" color="info" onClick={handlePostData}>
출간하기
</Button>
{/* <button className="px-4 py-2 font-bold text-green-400 duration-150 rounded hover:text-green-600">
임시저장
</button>
<button className="px-4 py-2 font-bold text-white duration-150 bg-green-500 rounded hover:bg-green-700">
출간하기
</button>
</button> */}
</div>
</div>
);
}

export default EditorFooter;
export default EditorFooter;
102 changes: 84 additions & 18 deletions src/components/EditorPage/MdEditor.jsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,104 @@
import React, { useState } from 'react';
import PostTitle from './PostTitle';
import EditerFooter from './EditorFooter';
import MDEditor from '@uiw/react-md-editor/nohighlight';
import '@uiw/react-md-editor/markdown-editor.css';
import '@uiw/react-markdown-preview/markdown.css';
import '../../styles/Editor.css';
import React, { useEffect, useState } from "react";
import PostTitle from "./PostTitle";
import EditerFooter from "./EditorFooter";
import Dropdown from "./Dropdown";
import MDEditor from "@uiw/react-md-editor/nohighlight";
import "@uiw/react-md-editor/markdown-editor.css";
import "@uiw/react-markdown-preview/markdown.css";
import "../../styles/Editor.css";
import { getAlgorithms, postTIL } from "../../api/detail";
import { useNavigate } from "react-router-dom";

function MdEditor() {
const [value, setValue] = useState("");
const [title, setTitle] = useState("");
const navigate = useNavigate();
const [postData, setPostData] = useState({
language: "",
site: "",
algorithmId: null,
title: "",
tag: "",
link: "",
codeContent: "",
content: "",
});
const [algorithmOptions, setAlgorithmOptions] = useState([]);
const algorithmNames = algorithmOptions.map((item) => item.korClassification);

const handleEditorChange = (newValue) => {
setValue(newValue);
const handlePostData = () => {
postTIL(postData).then((res) => navigate(`/posts/${res.data.id}`));
};

const handleDrop = async (event) => {
event.preventDefault();
const files = event.dataTransfer.files;
if (files.length > 0) {
const file = files[0];
const imageUrl = URL.createObjectURL(file);
setPostData((prev) => ({
...prev,
content: `${prev.content}\n![image](${imageUrl})`,
}));
}
};

useEffect(() => {
getAlgorithms().then((res) => setAlgorithmOptions(res.data.algorithmList));
}, []);

return (
<div className="flex h-screen" data-color-mode="light">
<div
className="flex h-screen"
data-color-mode="light"
onDrop={handleDrop}
onDragOver={(e) => e.preventDefault()}
>
<div className="flex flex-col w-full h-full sm:w-1/2">
<PostTitle title={title} setTitle={setTitle} />
<PostTitle
title={postData?.title}
onChange={(e) => setPostData({ ...postData, title: e.target.value })}
/>
<div className="flex px-1 m-3 space-x-2">
<Dropdown
name="site"
value={postData?.site}
options={["백준", "Programmers", "SWEA", "민코딩"]}
placeholder="사이트"
onChange={(e) => setPostData({ ...postData, site: e.target.value })}
/>
<Dropdown
name="language"
value={postData?.language}
options={["C", "Java", "Python"]}
placeholder="언어"
onChange={(e) =>
setPostData({ ...postData, language: e.target.value })
}
/>
<Dropdown
name="algorithm"
value={algorithmNames[postData.algorithmId - 1]}
options={algorithmNames}
placeholder="알고리즘"
onChange={(e) =>
setPostData({ ...postData, algorithmId: Number(e.target.value) })
}
/>
</div>
<MDEditor
height="100%"
value={value}
onChange={handleEditorChange}
value={postData?.content}
onChange={(value) => setPostData({ ...postData, content: value })}
preview="edit"
textareaProps={{
placeholder: "내용을 입력하세요.",
}}
/>
<EditerFooter />
<EditerFooter handlePostData={handlePostData} />
</div>
<div className="flex-col hidden w-1/2 h-full p-3 overflow-auto sm:flex bg-sky-50">
<div className="preview-content">
<MDEditor.Markdown
source={`# ${title}\n${value}`}
source={`# ${postData.title}\n${postData.content}`}
style={{ whiteSpace: "pre-wrap" }}
/>
</div>
Expand All @@ -41,4 +107,4 @@ function MdEditor() {
);
}

export default MdEditor;
export default MdEditor;
4 changes: 2 additions & 2 deletions src/components/EditorPage/PostTitle.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from 'react'

function PostTitle({ title, setTitle }) {
function PostTitle({ title, onChange }) {
return (
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
onChange={onChange}
placeholder="제목을 입력하세요"
className="pl-2 m-4 text-2xl font-bold text-gray-900 outline-none"
/>
Expand Down
Loading

0 comments on commit 69aab9d

Please sign in to comment.