Skip to content

An organization open to share knowledge and experience of web development in many aspects: tutorials, demos, walkthroughs, & challenges

Notifications You must be signed in to change notification settings

Arcane-404/arcane-404-blog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

96 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Arcane 404 Blog

Get Started

To run this project, we need a few things

  1. clone repo
HTTPS  : git clone https://github.com/Arcane-404/arcane-404-blog.git

SSH    : git clone git@github.com:Arcane-404/arcane-404-blog.git

GH-CLI : gh repo clone Arcane-404/arcane-404-blog
  1. cd ./arcane-404-blog
  2. git switch -c develop
  3. npm run update
    • check & merge any updates
    • install server-side packages
    • install client-side packages
  4. create .env
SKIP_PREFLIGHT_CHECK = true
JWT_TOKEN = secret
MONGODB_URI = [ db-link ]

# development: mongodb://localhost/[db-name]
# production: mongodb+srv://[db-user-name]:[db-password]@[server-cluster-name]:[port-number]/[db-name]
# e.g. mongodb+srv://the-arcane-404:the-password-404@foo123-shard-00-03-a1b2c.mongodb.net:27017/blog_app_db
  1. if Mac, enter chmod +x .husky/pre-commit
    • if Windows, skip this step
  2. start npm run dev

General Info

Folder Architecture

View client structure
arcane-404-blog/client/
โ”œโ”€ public/
โ”‚  โ”œโ”€ icons/
โ”‚  โ”‚  โ”œโ”€ favicon.ico
โ”‚  โ”œโ”€ index.html
โ”œโ”€ src/
โ”‚  โ”œโ”€ assets/
โ”‚  โ”œโ”€ components/
โ”‚  โ”œโ”€ constants/
โ”‚  โ”œโ”€ containers/
โ”‚  โ”œโ”€ contexts/
โ”‚  โ”œโ”€ hooks/
โ”‚  โ”œโ”€ json/
โ”‚  โ”œโ”€ pages/
โ”‚  โ”œโ”€ services/
โ”‚  โ”œโ”€ theme/
โ”‚  โ”œโ”€ utils/
โ”‚  โ”œโ”€ App.jsx
โ”‚  โ”œโ”€ index.js
โ”œโ”€ .env
โ€”
View server structure
arcane-404-blog/
โ”œโ”€ client/
โ”œโ”€ config/
โ”œโ”€ controllers/
โ”œโ”€ middlewares/
โ”œโ”€ models/
โ”œโ”€ routes/
index.js
View general structure
arcane-404-blog/
โ”œโ”€ .github/
โ”œโ”€ .husky/
โ”œโ”€ .env
โ”œโ”€ .editorconfig
โ”œโ”€ .eslintignore
โ”œโ”€ .eslintrc.json
โ”œโ”€ .gitignore
โ”œโ”€ .lintstagedrc.json
โ”œโ”€ .prettierignore
โ”œโ”€ .prettierrc.json
โ”œโ”€ index.js
โ”œโ”€ package.json
โ”œโ”€ README.md

Workflow Strategy

Our dev life cycle

General Workflow

  • #. Starting the day: pull all updates
  1. Work on branch off of develop
  2. Work on code
  3. Messageย theย reviewer
  • #.ย Ending the day: commit/push updates

Simple Workflow Checklist

  • Asana: create or update task 'To-Do'
  • VS Code + Git: branch, commit message, push
  • GitHub: manually create Pull Request
  • Asana: move task 'In Review'
  • Discord: message reviewer
  • VS Code + Git: pull, branch (create || continue)
  • Asana: update or move task 'In Progress'

Asana Task Strategy

  • 1 Epic initiative contains a unique Sprint # to follow any Tasks or Bugs
  • Epic: type branch name (descriptor)
  • Task: sub-tasks of commit messages

Git Branch Strategy

  • work on a support branch, PR to the develop branch, but never the main branch
  • core branch: main \ develop \ release
  • support branch: feature \ style \ fix \ chore \ test

Discord Review Strategy

  • submit any PR to review in the #๐ŸŽŸ-code-review
  • post @[username] [quick-message] [pull-request-link]

Block Component Strategy

  • Components are Connections to a Container that make a Page
  • building blocks of Atomic Design + Folder Structure
Our file naming convention
React
- components/: _Component.styles.js + index.jsx
- connections/: _Connection.jsx + _Connection.styles.js + index.jsx
- containers/: _Container.jsx + _Container.styles.js + index.jsx
- pages/: _CurrentPage.jsx
- services/: _User.services.js

Node
- controllers/: _User.controllers.js
- model/: _User.model.js
- routes/: _User.route.js

General
- index.js: single source path for each folder
- export { default as Component } from './[path]'
Our code guideline

Patterns to Follow

  • white-space
  • single quotes
  • no semi-colon
  • parent Component fn == arrow fn
    • deconstruct props
  • child helper fn == arrow fn
    • if fn has one line, then make it inline
    • else open to block scope, {}
  • callback fn
    • if single arg, none: fn(item โ‡’ ())
    • else, use (): fn((item, index) => ())
  • open brackets, not condensed

Code Sample

// rafce (shortcut) || rfc (default)
import React, { useState, useEffect } from 'react'
import { Button } from './components' // PascalCase

const isEmpty, hasKey, getRandomNumber // camelCase
const DESKTOP_SIZE = 1080 // CAP_CASE + fixed value
const arr = [ 'a', 'b', 'c' ]
const obj = { num1: 1, num2: 2, num3: 3 }

const Component = ({ num1, num2, num3 }) => {

  const [ count, setCount ] = useState('')

  // const handleClick = (e) => setCount(count + 1)

  const handleClick = (e) => {
    setCount(count + 1)
  }

  useEffect(() => {
    console.log('check state update:', count)
  }, [ num1, num2, num3 ])

  return (
	 <div>
  	<h2>Hooks Example: <code>{ count }</code></h2>
		<a { ...obj } obj={{ num4: 4 }}>show me</a>

		<button onClick={ handleClick }>increment</button>
    <button onClick={ (e) => console.log('+') }>log</button>

		{
		 arr.length && arr.map((item, index) => (
			<Button key={ uuid() }>{ item }</Button>
		 ))
		}

		{
		 Object.keys(obj).length && (
		  <>
			 <a href="#">Home Page</a>
			 <a href="#">About Page</a>
		  </>
		 )
		}
    </div>
  )
}

export default Component
Our block setup

more for block setup

Important Parts

  • components/
  • connections/
  • containers/
  • pages/

example: Login Form

components/

// create Button, Label, Input, ErrorText

// Button/ โ†’ _Button.styles.js
import { chakra, Button } from '@chakra-ui/react'
export const ButtonBox = chakra(Button, {})

// Button/ โ†’ _index.jsx
import React from 'react'
import { ButtonBox } from './_Button.styles'

export default function Button({ children, ...props }) {
	return <ButtonBox {...props}>{children}</ButtonBox>
}

// index.js
export { default as Button } from './Button'

containers/

// create TextField โ†’ Button + Label + Input + ErrorText

// TextField/ โ†’ _TextField.styles.js
import { chakra, FormControl } from '@chakra-ui/react'
export const TextFieldBox = chakra(FormControl, {})

// TextField/ โ†’ _TextField.jsx
import React from 'react'
import { TextFieldBox } from './_TextField.styles'
import { Label, Input, ErrorText } from '../components'

export default function TextField({ children, ...props }) {
	return <TextFieldBox {...props}>{children}</TextFieldBox>
}
TextField.Input = function TextField(props) {
	return <Input {...props} />
}
// ...

// TextField/ โ†’ index.jsx
import React, { useState } from 'react'
import TextField from './_TextField'

const TextFieldConnection = ({ type, name, label, placeholder, error }) => {
	const [value, setValue] = useState('')
	const onChange = (e) => setValue(e.target.value)

	const inputProps = {
		type,
		id: name,
		name,
		placeholder,
		value,
		onChange,
	}

	return (
		<TextField isInvalid={error}>
			<TextField.Label htmlFor={name} text={label} />
			<TextField.Input {...inputProps} />
			{error && <TextField.Error text={error.mesage} />}
		</TextField>
	)
}

// index.js
export { default as TextField } from './TextField'

containers/

// create LoginForm โ†’ Form + Heading, Submit

// LoginForm/ โ†’ _LoginForm.styles.js
import { chakra } from '@chakra-ui/react'
export const FormBox = chakra('form', {})

// LoginForm/ โ†’ _LoginForm.jsx
import React from 'react'
import { FormBox } from './_FormBox.styles'
import { Button } from '../components'

export default function LoginForm ({ children, ...props }) {
	return <FormBox { ...props }>{ children }</FormBox>
}
LoginForm.Submit = ({ children, ...props }) {
	return <Button { ...props }>{ children }</Button>
}
// ...

// LoginForm/ โ†’ index.jsx
import React, { useState } from 'react'
import LoginForm from './_LoginForm'
import { TextField } from '../connections'

const LoginFormContainer = () => {

	const [ values, setValues ] = useState('')
	const onSubmit = (e) => e.preventDefault()

	return (
		<LoginForm>
  		<LoginForm.Heading>Login</LoginForm.Heading>
      <TextField name="email" label="email" />
      <TextField name="password" label="Password" />
  		<LoginForm.Submit>Submit</LoginForm.Submit>
		</LoginForm>
	)
}

// index.js
export { default as LoginForm } from './LoginForm'

pages/

import React from 'react'
import { LoginForm } from '../containers'

const HomePage = () => {
	return (
		<>
			<LoginForm />
		</>
	)
}

DONE


Core Features

  • Register & verify a new user account
  • Login & verify a valid user account
  • view all our blog post article at the home page
  • select one blog post to view the whole content
  • for users, upvote or downvote the blog post
  • only for admins, submit a new blog post

API & DB Design

User

Method Path Description
POST /api/user/register enter new user account
POST /api/user/login enter existing user account
POST /api/user/validateToken verify if user is in a current session
{
  "username": { "STRING", "default": "anonymous" },
  "email": { "STRING", "required", "unique", "index" },
  "password": "STRING",
  "avatar": "STRING",
  "role": { "STRING", "default": "USER" },
  "createdAt": "DATE"
}

Blog

Method Path Description
GET /api/blog/all view all blog post
GET /api/blog/:id view one blog post from blog ID
POST /api/blog/create create one new blog post
PUT /api/blog/:id?vote=_ update up/down vote for specific blog post
{
	"author": {
		"id": { "ref": "USER" },
		"username": "STRING"
	},
	"title": "STRING",
	"body": "STRING",
	"upvote": [{ "ref": "USER" }],
	"downvote": [{ "ref": "USER" }],
	"createdOn": "DATE"
}

Tools & Technologies

Project Management

Asana Notion Discord Zoom

Design

Figma Design InVision

Develop

VS Code Git GitHub Postman

Front-End

React.js Chakra-UI React Router React Query
Emotion Framer Motion Formik Axios yup localforage Prop-Types

Back-End

Node.js Express.js JWT
Nodemon dotenv bcrypt yup morgan helmet cors

Database

MongoDB Mongoose (ODM)

Other

EditorConfig Prettier ESLint Lint-Staged Husky
concurrently npm-run-all rimraf serve

Mentions

RESTful API - CRUD - MVC

React Hooks - Compound-Components

Web Resources

Original Contributors

Profile Main Role Name (Username) Links
๐Ÿ–ผ Project Lead Michael F Alvarez (awwmicky) GitHub LinkedIn
๐Ÿ–ผ Front-End Dev Adnan Niaz (sanixstudio) GitHub LinkedIn
๐Ÿ–ผ Front-End Dev Mario Alvarez (mariofalvarez) GitHub LinkedIn
๐Ÿ–ผ Back-End Dev Herman Liu (hermsicle) GitHub LinkedIn
๐Ÿ–ผ Full Stack Dev Clarence Cheung (kleranscoding) GitHub

About

An organization open to share knowledge and experience of web development in many aspects: tutorials, demos, walkthroughs, & challenges

Resources

Stars

Watchers

Forks