Skip to content

Commit

Permalink
Merge pull request #14 from yoo-jimin127/feat/5_create-article
Browse files Browse the repository at this point in the history
Feat/5 create article
  • Loading branch information
yoo-jimin127 authored Jul 2, 2023
2 parents 63332cc + 3e12f0d commit 704a414
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 137 deletions.
14 changes: 13 additions & 1 deletion src/apis/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios from 'axios';
import { RegisterProps, LoginProps, SettingProps } from './types';
import { RegisterProps, LoginProps, SettingProps, ArticleProps } from './types';

const baseURL = `https://api.realworld.io/api`;
const token = localStorage.getItem('token');
Expand Down Expand Up @@ -53,3 +53,15 @@ export const getFavoritedArticles = async (username: string) => {
});
return res.data;
};

export const createArticle = async ({ title, description, body, tagList }: ArticleProps) => {
const res = await authHttp.post(`${baseURL}/articles`, {
article: { title, description, body, tagList },
});
return res.data;
}

export const getArticle = async (slug: string) => {
const res = await http.get(`/articles/${slug}`);
return res.data;
}
11 changes: 10 additions & 1 deletion src/apis/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ export interface RegisterProps {
email: string;
password: string;
}

export interface LoginProps {
email: string;
password: string;
}

export interface SettingProps {
email: string;
password: string;
Expand All @@ -15,7 +17,7 @@ export interface SettingProps {
image: string;
}

export interface ArticleProps {
export interface ArticleListProps {
slug: string;
title: string;
description: string;
Expand All @@ -32,3 +34,10 @@ export interface ArticleProps {
following: boolean;
};
}

export interface ArticleProps {
title: string,
description: string,
body: string,
tagList: string[],
}
204 changes: 107 additions & 97 deletions src/pages/Article.tsx
Original file line number Diff line number Diff line change
@@ -1,112 +1,122 @@
import { useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import { getArticle } from '../apis';
import { ArticleListProps } from '../apis/types';

function Article() {
return <div className="article-page">
<div className="banner">
<div className="container">
<h1>How to build webapps that scale</h1>
const [articleContent, setArticleContent] = useState<ArticleListProps>();
const { articleSlug } = useParams();

<div className="article-meta">
<a href=""><img src="http://i.imgur.com/Qr71crq.jpg"/></a>
<div className="info">
<a href="" className="author">Eric Simons</a>
<span className="date">January 20th</span>
</div>
<button className="btn btn-sm btn-outline-secondary">
<i className="ion-plus-round"/>
&nbsp; Follow Eric Simons <span className="counter">(10)</span>
</button>
&nbsp;&nbsp;
<button className="btn btn-sm btn-outline-primary">
<i className="ion-heart"/>
&nbsp; Favorite Post <span className="counter">(29)</span>
</button>
</div>
</div>
</div>
const fetchArticle = async (slug: string) => {
const { article } = await getArticle(slug);
setArticleContent(article);
};

useEffect(() => {
fetchArticle(articleSlug as string);
}, [articleContent]);

return (
<div className="article-page">
<div className="banner">
<div className="container">
<h1>{articleContent?.title}</h1>

<div className="container page">
<div className="row article-content">
<div className="col-md-12">
<p>
Web development technologies have evolved at an incredible clip over the past few years.
</p>
<h2 id="introducing-ionic">Introducing RealWorld.</h2>
<p>It's a great solution for learning how other frameworks work.</p>
</div>
<div className="article-meta">
<a href="/">
<img src="http://i.imgur.com/Qr71crq.jpg" alt="" />
</a>
<div className="info">
<a href="/" className="author">
{articleContent?.author.username}
</a>
<span className="date">January 20th</span>
</div>
<button className="btn btn-sm btn-outline-secondary" type="button">
<i className="ion-plus-round" />
&nbsp; Follow {articleContent?.author.username} <span className="counter">({})</span>
</button>
&nbsp;&nbsp;
<button className="btn btn-sm btn-outline-primary" type="button">
<i className="ion-heart" />
&nbsp; Favorite Article{' '}
<span className="counter">({articleContent?.favoritesCount})</span>
</button>
</div>
</div>
</div>

<hr/>
<div className="container page">
<div className="row article-content">
<div className="col-md-12">
<p>{articleContent?.body}</p>
{/* TODO : 무슨 내용 들어가야 하는지 조사 */}
<h2 id="introducing-ionic">{articleContent?.description}</h2>
<p>{articleContent?.body}</p>
</div>
</div>

<div className="article-actions">
<div className="article-meta">
<a href="profile.html"><img src="http://i.imgur.com/Qr71crq.jpg"/></a>
<div className="info">
<a href="" className="author">Eric Simons</a>
<span className="date">January 20th</span>
</div>
<hr />

<button className="btn btn-sm btn-outline-secondary">
<i className="ion-plus-round"/>
&nbsp; Follow Eric Simons
</button>
&nbsp;
<button className="btn btn-sm btn-outline-primary">
<i className="ion-heart"/>
&nbsp; Favorite Post <span className="counter">(29)</span>
</button>
</div>
<div className="article-actions">
<div className="article-meta">
<a href="profile.html">
<img src="http://i.imgur.com/Qr71crq.jpg" alt="" />
</a>
<div className="info">
<a href="/" className="author">
{articleContent?.author.username}
</a>
<span className="date">{articleContent?.createdAt}</span>
</div>
<button className="btn btn-sm btn-outline-secondary" type="button">
<i className="ion-plus-round" />
&nbsp; Follow {articleContent?.author.username}
</button>
&nbsp;
<button className="btn btn-sm btn-outline-primary" type="button">
<i className="ion-heart" />
&nbsp; Favorite Post <span className="counter">({articleContent?.favoritesCount})</span>
</button>
</div>
</div>

<div className="row">
<div className="col-xs-12 col-md-8 offset-md-2">
<form className="card comment-form">
<div className="card-block">
<textarea className="form-control" placeholder="Write a comment..." rows="3"></textarea>
</div>
<div className="card-footer">
<img src="http://i.imgur.com/Qr71crq.jpg" className="comment-author-img"/>
<button className="btn btn-sm btn-primary">Post Comment</button>
</div>
</form>

<div className="card">
<div className="card-block">
<p className="card-text">
With supporting text below as a natural lead-in to additional content.
</p>
</div>
<div className="card-footer">
<a href="" className="comment-author">
<img src="http://i.imgur.com/Qr71crq.jpg" className="comment-author-img"/>
</a>
&nbsp;
<a href="" className="comment-author">Jacob Schmidt</a>
<span className="date-posted">Dec 29th</span>
</div>
</div>
<div className="row">
<div className="col-xs-12 col-md-8 offset-md-2">
<form className="card comment-form">
<div className="card-block">
<textarea className="form-control" placeholder="Write a comment..." />
</div>
<div className="card-footer">
<img src="http://i.imgur.com/Qr71crq.jpg" className="comment-author-img" alt="" />
<button className="btn btn-sm btn-primary" type="button">
Post Comment
</button>
</div>
</form>

<div className="card">
<div className="card-block">
<p className="card-text">
With supporting text below as a natural lead-in to additional content.
</p>
</div>
<div className="card-footer">
<a href="" className="comment-author">
<img src="http://i.imgur.com/Qr71crq.jpg" className="comment-author-img"/>
</a>
&nbsp;
<a href="" className="comment-author">Jacob Schmidt</a>
<span className="date-posted">Dec 29th</span>
<span className="mod-options">
<i className="ion-edit"></i>
<i className="ion-trash-a"></i>
</span>
</div>
</div>
</div>
<div className="card">
<div className="card-block">
<p className="card-text">
With supporting text below as a natural lead-in to additional content.
</p>
</div>
<div className="card-footer">
<a href="/" className="comment-author">
<img src="http://i.imgur.com/Qr71crq.jpg" className="comment-author-img" alt="" />
</a>
&nbsp;
<a href="/" className="comment-author">
Jacob Schmidt
</a>
<span className="date-posted">Dec 29th</span>
</div>
</div>
</div>
</div>
</div>;
</div>
</div>
);
}

export default Article;
102 changes: 70 additions & 32 deletions src/pages/CreateArticle.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,75 @@
import { ChangeEvent, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { createArticle } from '../apis';

function CreateArticle() {
return <div className="editor-page">
<div className="container page">
<div className="row">
<div className="col-md-10 offset-md-1 col-xs-12">
<form>
<fieldset>
<fieldset className="form-group">
<input type="text" className="form-control form-control-lg"
placeholder="Article Title"/>
</fieldset>
<fieldset className="form-group">
<input type="text" className="form-control" placeholder="What's this article about?"/>
</fieldset>
<fieldset className="form-group">
<textarea
className="form-control"
rows={8}
placeholder="Write your article (in markdown)"
/>
</fieldset>
<fieldset className="form-group">
<input type="text" className="form-control" placeholder="Enter tags"/>
<div className="tag-list"/>
</fieldset>
<button className="btn btn-lg pull-xs-right btn-primary" type="button">
Publish Article
</button>
</fieldset>
</form>
</div>
</div>
const navigate = useNavigate();
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [body, setBody] = useState('');
const [tagList, setTagList] = useState<string[]>([]);

const handleSubmit = async (event: ChangeEvent<HTMLFormElement>) => {
event.preventDefault();
const { article } = await createArticle({ title, description, body, tagList });
const { slug } = article;
navigate(`/article/${slug}`);
};

return (
<div className="editor-page">
<div className="container page">
<div className="row">
<div className="col-md-10 offset-md-1 col-xs-12">
<form onSubmit={handleSubmit}>
<fieldset>
<fieldset className="form-group">
<input
type="text"
className="form-control form-control-lg"
placeholder="Article Title"
value={title}
onChange={(event) => setTitle(event.target.value)}
/>
</fieldset>
<fieldset className="form-group">
<input
type="text"
className="form-control"
placeholder="What's this article about?"
value={description}
onChange={(event) => setDescription(event.target.value)}
/>
</fieldset>
<fieldset className="form-group">
<textarea
className="form-control"
rows={8}
placeholder="Write your article (in markdown)"
value={body}
onChange={(event) => setBody(event.target.value)}
/>
</fieldset>
<fieldset className="form-group">
<input
type="text"
className="form-control"
placeholder="Enter tags"
value={tagList}
onChange={(event) => setTagList([...tagList, event.target.value])}
/>
<div className="tag-list" />
</fieldset>
<button className="btn btn-lg pull-xs-right btn-primary" type="submit">
Publish Article
</button>
</fieldset>
</form>
</div>
</div>
</div>;
</div>
</div>
);
}

export default CreateArticle;
Loading

0 comments on commit 704a414

Please sign in to comment.