Skip to content

Instantly share code, notes, and snippets.

@erwanriou
Created November 20, 2019 09:40
Show Gist options
  • Save erwanriou/49cc72692058b1492c556d57bb4e2611 to your computer and use it in GitHub Desktop.
Save erwanriou/49cc72692058b1492c556d57bb4e2611 to your computer and use it in GitHub Desktop.
Redux flow for a blog
import axios from "axios"
import {
GET_ERRORS,
ARTICLE_RESET_STATE,
ARTICLE_FETCH,
ARTICLES_FETCH,
ARTICLES_LIKE,
ARTICLE_LIKE
} from "../types"
import { loading, clearLoading } from "./loadingActions"
export const fetchAllPublicArticles = (
category,
countryCode,
query
) => async dispatch => {
dispatch(loading())
try {
// DEFINE QUERY
const config = {
params: {
countryCode,
title: query
}
}
// CALL API
const res = await axios.get(`/api/global/article/${category}`, config)
dispatch({
type: ARTICLES_FETCH,
payload: res.data
})
} catch (e) {
dispatch({
type: GET_ERRORS,
payload: e.response.data
})
}
dispatch(clearLoading())
}
// FETCH ONE ARTICLE
export const fetchAllPublicArticle = (
category,
url,
countryCode,
history
) => async dispatch => {
dispatch(loading())
try {
// DEFINE QUERY
const config = {
params: {
countryCode
}
}
// CALL API
const res = await axios.get(
`/api/global/article/${category}/${url}`,
config
)
dispatch({
type: ARTICLE_FETCH,
payload: res.data
})
} catch (e) {
dispatch({
type: GET_ERRORS,
payload: e.response.data
})
history.push("/not-found")
}
dispatch(clearLoading())
}
// LIKE OR UNLIKE ARTICLES
export const likeArticle = (id, url) => async dispatch => {
dispatch(loading())
try {
const res = await axios.post(`/api/global/article/favorite/${id}`)
window.location.pathname.includes(url)
? dispatch({
type: ARTICLE_LIKE,
payload: res.data
})
: dispatch({
type: ARTICLES_LIKE,
payload: res.data,
id
})
} catch (e) {
dispatch({
type: GET_ERRORS,
payload: e.response.data
})
}
dispatch(clearLoading())
}
export const cleanArticleState = () => async dispatch => {
dispatch({
type: ARTICLE_RESET_STATE
})
}
const express = require("express")
const mongoose = require("mongoose")
const passport = require("passport")
const apicache = require("apicache")
const { getCode } = require("country-list")
// IMPORT MIDDLEWARE AND MODELS
const Article = require("../../../models/Article")
const cache = apicache.middleware
// IMPORT VALIDATION
const isEmpty = require("../../../validation/is-empty")
const router = express.Router()
// @route GET api/global/article/post
// @desc Get all approved publications
// @access Public
router.get("/post", cache("1 hour"), async (req, res) => {
try {
let articleQuery
isEmpty(req.query.title)
? (articleQuery = "")
: (articleQuery = req.query.title
.toLowerCase()
.split("%20")
.join(" "))
const articles = await Article.find({
isActivated: true,
category: "POST",
country: { $in: [req.query.countryCode] },
title: {
$regex: new RegExp(articleQuery, "i")
}
})
res.status(200).json(articles)
} catch (err) {
res.status(400).json(err)
}
})
// @route GET api/global/article/post
// @desc Get all approved publications
// @access Public
router.get("/post/:url", cache("1 hour"), async (req, res) => {
try {
const errors = {}
const url = req.params.url.toLowerCase()
const article = await Article.findOne({
url: req.params.url,
isActivated: true,
country: { $in: [req.query.countryCode] },
category: "POST"
})
if (!article) {
errors.noprofile = "There is no Article existing"
return res.status(404).json(errors)
}
res.status(200).json(article)
} catch (err) {
res.status(400).json(err)
}
})
// @route GET api/global/article/post
// @desc Get all approved partners
// @access Public
router.get("/partner", async (req, res) => {
try {
let articleQuery
isEmpty(req.query.title)
? (articleQuery = "")
: (articleQuery = req.query.title
.toLowerCase()
.split("%20")
.join(" "))
const articles = await Article.find({
isActivated: true,
category: "PARTNER",
country: { $in: [req.query.countryCode] },
title: {
$regex: new RegExp(articleQuery, "i")
}
})
res.status(200).json(articles)
} catch (err) {
res.status(400).json(err)
}
})
// @route POST api/global/article/favorite/:id
// @desc Like or Unlike article
// @access Private
router.post(
"/favorite/:id",
passport.authenticate("jwt", { session: false }),
async (req, res) => {
try {
const article = await Article.findById(req.params.id)
const indexOfUser = article.favorite.findIndex(
favorite => favorite.user.toString() === req.user.id
)
indexOfUser === -1
? article.favorite.unshift({ user: req.user.id })
: article.favorite.splice(indexOfUser, 1)
await article.save()
return res.status(200).json(article.favorite)
} catch (err) {
res.status(400).json(err)
}
}
)
module.exports = router
import {
LOADING_DATA,
CLEAR_LOADING_DATA,
ARTICLE_RESET_STATE,
ARTICLE_FETCH,
ARTICLES_FETCH,
ARTICLE_NEW,
ARTICLES_LIKE,
ARTICLE_LIKE,
ARTICLE_IMAGE_UPLOAD,
ARTICLE_ACTIVATE,
ARTICLE_UPDATE_STATUS
} from "../actions/types"
const initialState = {
articles: [],
article: {},
drafts: [],
total: "",
loading: false
}
export default function articleReducer(state = initialState, action) {
switch (action.type) {
case LOADING_DATA:
return {
...state,
loading: true
}
case ARTICLES_FETCH:
return {
...state,
articles: action.payload,
loading: false
}
case ARTICLE_FETCH:
return {
...state,
article: action.payload,
loading: false
}
case ARTICLE_NEW:
return {
...state,
articles: [...state.articles, action.payload],
loading: false
}
case ARTICLE_ACTIVATE:
return {
...state,
articles: [
...state.articles.map(article => {
if (article._id === action.id) {
return {
...article,
isActivated: action.payload
}
} else {
return article
}
})
],
loading: false
}
case ARTICLE_UPDATE_STATUS:
return {
...state,
articles: [
...state.articles.map(article => {
if (article._id === action.id) {
return {
...article,
category: action.payload
}
} else {
return article
}
})
],
loading: false
}
case ARTICLE_IMAGE_UPLOAD:
const image = { url: action.payload.key }
return {
...state,
drafts: [...state.drafts, image],
loading: false
}
case ARTICLES_LIKE:
return {
...state,
articles: [
...state.articles.map(article => {
if (article._id === action.id) {
return {
...article,
favorite: action.payload
}
} else {
return article
}
})
],
loading: false
}
case ARTICLE_LIKE:
return {
...state,
article: {
...state.article,
favorite: action.payload
}
}
case CLEAR_LOADING_DATA:
return {
...state,
loading: false
}
case ARTICLE_RESET_STATE:
return {
...state,
articles: []
}
default:
return state
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment