feat : [FE] Article Update ADD.

This commit is contained in:
minseokkang
2022-12-05 19:01:06 +09:00
parent 74451508e9
commit 427eae6efd
6 changed files with 218 additions and 49 deletions

View File

@@ -74,6 +74,16 @@ const createArticle = async (article: object | undefined): Promise<AxiosResponse
})
}
const updateArticle = async (article: object | undefined, slug: string): Promise<AxiosResponse> => {
let currentToken = localStorage.getItem("token");
return await axiosService.put('/api/articles/' + slug, { article },{
headers :{
Authorization : "TOKEN " + currentToken,
"Content-Type": `application/json`,
}
})
}
const listArticles = async (): Promise<AxiosResponse> => {
let currentToken = localStorage.getItem("token");
if(currentToken == null){
@@ -100,6 +110,19 @@ const listArticlesByUsername = async (author: string): Promise<AxiosResponse> =>
}
}
const listArticlesByFavorite = async (author: string): Promise<AxiosResponse> => {
let currentToken = localStorage.getItem("token");
if(currentToken == null){
return await axiosService.get('/api/articles?favorited=' + author);
}else{
return await axiosService.get('/api/articles?favorited=' + author,{
headers:{
Authorization: "TOKEN " + currentToken,
}
})
}
}
const feedArticle = async (): Promise<AxiosResponse> => {
let currentToken = localStorage.getItem("token");
return await axiosService.get('/api/articles/feed?limit=1000&offset=0',{
@@ -182,5 +205,6 @@ export { signUp, signIn,
unfollowUser, getArticle,
addCommentToArticle, getCommentsFromArticle,
favoriteArticle, unFavoriteArticle,
listArticlesByFavorite, updateArticle,
getTags
}

View File

@@ -1,5 +1,5 @@
import { ref, Ref } from "@vue/reactivity";
import { listArticles, feedArticle } from "@/api/index";
import {listArticles, feedArticle, listArticlesByUsername, listArticlesByFavorite} from "@/api/index";
import { usePagination } from "@/ts/usePagination";
@@ -63,11 +63,45 @@ export function usePaginationApi(
}
};
const loadMyArticles = async (author: string) => {
listsAreLoading.value = true;
isEmpty.value = false;
try{
const { data } = await listArticlesByUsername(author);
articleLists.value = data.articles;
if(data.articlesCount == 0){
isEmpty.value = true;
}
}catch (err){
console.log(err);
}finally {
listsAreLoading.value = false;
}
}
const loadFavoriteArticles = async (author: string) => {
listsAreLoading.value = true;
isEmpty.value = false;
try{
const { data } = await listArticlesByFavorite(author);
articleLists.value = data.articles;
if(data.articlesCount == 0){
isEmpty.value = true;
}
}catch (err){
console.log(err);
}finally {
listsAreLoading.value = false;
}
}
return {
articleLists: paginatedArray,
loadLists,
feedLists,
loadMyArticles,
loadFavoriteArticles,
listsAreLoading,
isEmpty,
numberOfPages

View File

@@ -33,6 +33,12 @@ const routes = [
name: "ArticleEditor",
component: () => import(/* webpackChunkName "inputTag" */ '@/views/TheArticle.vue')
},
{
path: "/editor/@:slug",
name: "ArticleUpdateEditor",
component: () => import(/* webpackChunkName "inputTag" */ '@/views/ArticleUpdate.vue'),
props: true
},
{
path: "/@:username",
name: "Profile",

View File

@@ -0,0 +1,74 @@
<template>
<div class="editor-page">
<div class="container page">
<div class="row">
<div class="col-md-10 offset-md-1 col-xs-12">
<form>
<fieldset>
<fieldset class="form-group">
<input type="text" class="form-control form-control-lg" placeholder="Article Title" v-model="article.title">
</fieldset>
<fieldset class="form-group">
<input type="text" class="form-control" placeholder="What's this article about?" v-model="article.description">
</fieldset>
<fieldset class="form-group">
<textarea class="form-control" rows="8"
placeholder="Write your article (in markdown)" v-model="article.body"></textarea>
</fieldset>
<fieldset class="form-group">
<input type="text" class="form-control" placeholder="Enter tags using ',' Add tag">
<div class="tag-list"></div>
</fieldset>
<button @click="updateContent" class="btn btn-lg pull-xs-right btn-primary" type="button">
Publish Article
</button>
</fieldset>
</form>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { reactive } from "vue";
import { updateArticle } from "@/api/index.js";
import router from "@/router";
export default {
name: "ArticleUpdate",
props:{
slug: String,
},
setup(){
const article = reactive({
title: "",
description: "",
body: "",
})
const getSlug = (title:string) => {
return title.replace(' ','-');
}
const updateContent = async () => {
const slug = getSlug(article.title);
try{
await updateArticle(article, slug);
await router.push({
name:"ArticleDetail",
params: {slug}
})
}catch (error: any){
alert(error);
}
}
return { article, updateContent }
}
}
</script>
<style scoped>
</style>

View File

@@ -12,7 +12,15 @@
<a href="javascript:void(0)" class="author" @click="viewProfile">{{ articleDetail.article.author.username }}</a>
<span class="date">{{convertDate(articleDetail.article.createdAt)}}</span>
</div>
<button class="btn btn-sm btn-outline-secondary" @click="followUpdate(articleDetail.article.author.following)">
<button v-if= "isMe" class="btn btn-sm btn-outline-secondary" @click="articleUpdate()">
<i class="ion-edit"></i>
Edit Article
</button>
<button v-if= "isMe" class="btn btn-outline-danger btn-sm" @click="followUpdate(articleDetail.article.author.following)">
<i class="ion-trash-a"></i>
Delete Article
</button>
<button v-if= "!isMe" class="btn btn-sm btn-outline-secondary" @click="followUpdate(articleDetail.article.author.following)">
<div v-if="articleDetail.article.author.following">
<i class="ion-minus-round"></i>
unFollow {{articleDetail.article.author.username}}
@@ -23,7 +31,7 @@
</div>
</button>
&nbsp;&nbsp;
<button class="btn btn-sm btn-outline-primary" @click="favoriteUpdate(articleDetail.article.favorited)">
<button v-if="!isMe" class="btn btn-sm btn-outline-primary" @click="favoriteUpdate(articleDetail.article.favorited)">
<div v-if="articleDetail.article.favorited">
<i class="ion-heart"></i>
unFavorite Article (<span class="counter">{{articleDetail.article.favoritesCount}}</span>)
@@ -45,7 +53,6 @@
{{articleDetail.article.body}}
</div>
</div>
<hr/>
<div class="article-actions">
@@ -55,7 +62,15 @@
<a href="javascript:void(0)" class="author" @click="viewProfile">{{ articleDetail.article.author.username }}</a>
<span class="date">{{convertDate(articleDetail.article.createdAt)}}</span>
</div>
<button class="btn btn-sm btn-outline-secondary" @click="followUpdate(articleDetail.article.author.following)">
<button v-if= "isMe" class="btn btn-sm btn-outline-secondary" @click="followUpdate(articleDetail.article.author.following)">
<i class="ion-edit"></i>
Edit Article
</button>
<button v-if= "isMe" class="btn btn-outline-danger btn-sm" @click="followUpdate(articleDetail.article.author.following)">
<i class="ion-trash-a"></i>
Delete Article
</button>
<button v-if= "!isMe" class="btn btn-sm btn-outline-secondary" @click="followUpdate(articleDetail.article.author.following)">
<div v-if="articleDetail.article.author.following">
<i class="ion-minus-round"></i>
unFollow {{articleDetail.article.author.username}}
@@ -65,13 +80,13 @@
Follow {{articleDetail.article.author.username}}
</div>
</button>
&nbsp;
<button class="btn btn-sm btn-outline-primary" @click="favoriteUpdate(articleDetail.article.favorited)">
&nbsp;&nbsp;
<button v-if="!isMe" class="btn btn-sm btn-outline-primary" @click="favoriteUpdate(articleDetail.article.favorited)">
<div v-if="articleDetail.article.favorited">
<i class="ion-heart"></i>
unFavorite Article (<span class="counter">{{articleDetail.article.favoritesCount}}</span>)
</div>
&nbsp;<div v-else>
<div v-else>
<i class="ion-heart"></i>
Favorite Article (<span class="counter">{{articleDetail.article.favoritesCount}}</span>)
</div>
@@ -109,7 +124,7 @@
</template>
<script lang="ts">
import { onMounted, defineComponent, reactive } from "vue";
import {onMounted, defineComponent, reactive, ref} from "vue";
import commentList from "@/components/commentList.vue";
import router from "@/router";
import { useStore } from "vuex";
@@ -134,6 +149,8 @@ export default defineComponent({
setup(props){
const store = useStore();
const token = store.state.token;
const username = store.state.username;
const isMe = ref(false);
const comment = reactive({
body: ""
@@ -169,6 +186,13 @@ export default defineComponent({
params: {username: articleDetail.article.author.username}})
}
const articleUpdate = async () => {
await router.push({
name: 'ArticleEditor',
params: {slug: articleDetail.article.slug}
})
}
const followUpdate = async (followState: boolean) => {
if(token == ''){
await router.push({name:"Login"});
@@ -221,6 +245,9 @@ export default defineComponent({
try{
const { data } = await getArticle(props.slug);
articleDetail.article = data.article;
if(articleDetail.article.author.username == username){
isMe.value = true;
}
}catch (error: any){
alert(error);
}
@@ -233,7 +260,7 @@ export default defineComponent({
}
})
return { articleDetail, comment, getCommentList, convertDate, viewProfile, followUpdate, favoriteUpdate, sendComment }
return { isMe, articleDetail, comment, getCommentList, convertDate, viewProfile, articleUpdate, followUpdate, favoriteUpdate, sendComment }
}
})
</script>

View File

@@ -1,11 +1,8 @@
<template>
<div class="profile-page">
<div class="user-info">
<div class="container">
<div class="row">
<div class="col-xs-12 col-md-10 offset-md-1">
<img :src="profile.image" class="user-img"/>
<h4>{{ profile.username }}</h4>
@@ -29,7 +26,6 @@
</div>
</button>
</div>
</div>
</div>
</div>
@@ -41,19 +37,29 @@
<div class="articles-toggle">
<ul class="nav nav-pills outline-active">
<li class="nav-item">
<a class="nav-link active" href="javascript">My Articles</a>
<a href="javascript:(0)" class="nav-link"
@click="myArticleSelect"
:class="{ active : myArticleActive}">My Articles</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">Favorited Articles</a>
<a href="javascript:(0)" class="nav-link"
@click="favoriteArticleSelect"
:class="{ active : favoriteArticleActive}">Favorited Articles</a>
</li>
</ul>
<div v-if="listsAreLoading">
Loading articles...
</div>
<div v-if="isEmpty">
No articles are here... yet.
</div>
</div>
<article-my v-for="(art,index) in articles.article"
:article="art">
</article-my>
<article-my v-for="(article,index) in articleLists"
:key="article.slug"
:article="article">
</article-my>
<pagination-component v-model="currentPage" :numberOfPages="numberOfPages"></pagination-component>
</div>
</div>
</div>
@@ -64,23 +70,23 @@
import { onMounted, reactive, ref } from "vue";
import { useStore } from "vuex";
import { defineComponent } from 'vue';
import pagination from "@/components/PaginationComponent.vue";
import { usePaginationApi } from "@/api/usePaginationAPI"
import router from "@/router";
import { followUser, getProfile, listArticlesByUsername, unfollowUser } from "@/api";
import { followUser, getProfile, unfollowUser } from "@/api";
import ArticleMy from "@/components/ArticleMy.vue";
export default defineComponent({
name: "TheProfile.vue",
components: {
"article-my": ArticleMy,
'pagination-component': pagination,
},
props:{
username: String,
},
setup(props){
const url = import.meta.env.VITE_BASE_URL;
const store = useStore();
const isMe = ref(false);
const profile = reactive({
image: "",
@@ -88,26 +94,14 @@ export default defineComponent({
bio: "",
following: false,
})
const myArticleActive = ref(true);
const favoriteArticleActive = ref(false);
const articles = reactive({
article: reactive([{
slug: "",
title: "",
description: "",
body: "",
tagList: new Array(),
createdAt: "",
updatedAt: "",
favorited: false,
favoritesCount: 0,
author: {
username: "",
bio: "",
image: "",
following: false
}
}])
})
const currentPage = ref(1);
const rowsPerPage = ref(5);
const { articleLists, listsAreLoading, isEmpty,loadMyArticles, loadFavoriteArticles, numberOfPages } = usePaginationApi(currentPage, rowsPerPage);
const setProfile = async ( data: any ) => {
profile.image = data.image;
@@ -138,10 +132,22 @@ export default defineComponent({
}
}
const myArticleSelect = async () => {
myArticleActive.value=true;
favoriteArticleActive.value=false;
await loadMyArticles(profile.username);
}
const favoriteArticleSelect = async () => {
myArticleActive.value=false;
favoriteArticleActive.value=true;
await loadFavoriteArticles(profile.username);
}
onMounted(async () =>{
try {
const { data } = await getProfile(props.username)
const { data } = await getProfile(props.username)
await setProfile(data.profile);
if(data.profile.username.localeCompare(store.state.username) == 0){
isMe.value = true;
@@ -153,15 +159,13 @@ export default defineComponent({
if(code == "USER_NOT_FOUND")
await router.push({name:"home"});
}
try{
const { data } = await listArticlesByUsername(profile.username);
articles.article = data.articles;
await loadMyArticles(profile.username);
}catch (error: any){
alert(error);
}
})
return { url, isMe, profile, articles, stateUpdate }
return { isMe, listsAreLoading, isEmpty, myArticleActive, favoriteArticleActive, profile, articleLists, currentPage, rowsPerPage, stateUpdate, myArticleSelect, favoriteArticleSelect, numberOfPages }
}
})
</script>