Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
MargoMarm authored Sep 14, 2023
0 parents commit 7c06d63
Show file tree
Hide file tree
Showing 39 changed files with 11,857 additions and 0 deletions.
1 change: 1 addition & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_API_TEST=Hello,world
21 changes: 21 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
'prettier'
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
26 changes: 26 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Build and deploy to GitHub Pages

on:
push:
branches: [main]
env:
VITE_API_TEST: ${{secrets.VITE_API_TEST}}

jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3

- name: Install, build 🔧
run: |
npm install
npm run build
cp ./dist/index.html ./dist/404.html
- name: Deploy 🚀
uses: JamesIves/[email protected]
with:
branch: gh-pages
folder: dist
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.env
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged
5 changes: 5 additions & 0 deletions .huskyrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"hooks": {
"pre-commit": "lint-staged"
}
}
4 changes: 4 additions & 0 deletions .lintstagedrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"src/**/*.{json,css,scss,md}": ["prettier --write"],
"src/**/*.{js,jsx,ts,tsx}": ["prettier --write", "eslint --fix"]
}
12 changes: 12 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "avoid",
"proseWrap": "always"
}
108 changes: 108 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# React + Vite template

Цей проєкт було створено за допомогою [Create Vite](https://vitejs.dev/). Для
знайомства і налаштування додаткових можливостей
[звернися до документації](https://vitejs.dev/guide/).

## Створення репозиторію за шаблоном

Використовуй цей репозиторій організації GoIT як шаблон для створення
репозиторію свого проєкту. Для цього натисни на кнопку `"Use this template"` і
обери опцію `"Create a new repository"`, як показано на зображенні.

![Creating repo from a template step 1](./src/assets/template-step-1.png)

На наступному кроці відкриється сторінка створення нового репозиторію. Заповни
поле його імені, переконайся що репозиторій публічний, після чого натисни кнопку
`"Create repository from template"`.

![Creating repo from a template step 2](./src/assets/template-step-2.png)

Після того як репозиторій буде створено, необхідно перейти в налаштування
створеного репозиторію на вкладку `Settings` > `Actions` > `General` як показано
на зображенні.

![Settings GitHub Actions permissions step 1](./src/assets/gh-actions-perm-1.png)

Проскроливши сторінку до самого кінця, у секції `"Workflow permissions"` вибери
опцію `"Read and write permissions"` і постав галочку в чекбоксі. Це необхідно
для автоматизації процесу деплою проєкту.

![Settings GitHub Actions permissions step 2](./src/assets/gh-actions-perm-2.png)

Тепер у тебе є особистий репозиторій проєкту, зі структурою файлів і папок
репозиторія-шаблону. Далі працюй з ним як з будь-яким іншим особистим
репозиторієм, клонуй його собі на комп'ютер, пиши код, роби комміти і відправляй
їх на GitHub.

## Підготовка до роботи

1. Переконайся, що на комп'ютері встановлена LTS-версія Node.js.
[Скачай і встанови](https://nodejs.org/en/) її якщо необхідно.
2. Встановіть базові залежності проекту командою `npm install`.
3. Запустіть режим розробки, виконавши команду `npm run dev`.
4. Перейди в браузері за адресою, що зазначено в терміналі.

## Деплой

Продакшн версія проєкту буде автоматично збиратися і деплоїтися на GitHub Pages,
у гілку `gh-pages`, щоразу, коли оновлюється гілка `main`. Наприклад, після
прямого пушу або прийнятого пул-реквесту. Для цього необхідно у файлі
`vite.config.js` відредагувати поле `base`, замінивши `react_vite` на свою назву
репозиторію `"/your_repo_name"`, і відправити зміни на GitHub.

Далі необхідно зайти в налаштування GitHub-репозиторію (`Settings` > `Pages`) і
виставити роздачу продакшн версії файлів із папки `/root` гілки `gh-pages`, якщо
це не було зроблено автоматично.

![GitHub Pages settings](./src/assets/repo-settings.png)

### Статус деплоя

Статус деплою крайнього коміту відображається іконкою біля його ідентифікатора.

- **Жовтий колір** - виконується збірка і деплой проєкту.
- **Зелений колір** - деплой завершився успішно.
- **Червоний колір** - під час збирання або деплою сталася помилка.

Детальнішу інформацію про статус можна подивитися, клікнувши на іконку, і в
випадаючому вікні перейти за посиланням `Details`.

![Deployment status](./src/assets/deploy-status.png)

### Жива сторінка

Через якийсь час, зазвичай кілька хвилин, живу сторінку можна буде подивитися за
адресою, вказаною в налаштуваннях GitHub-репозиторію (`Settings` > `Pages`).

![GitHub-pages URL](./src/assets/gh-pages-url.png)

Якщо відкривається порожня сторінка, переконайся що у вкладці `Console` немає
помилок пов'язаних із неправильними шляхами до CSS і JS файлів проекту
(**404**). Швидше за все найімовірніше, у тебе неправильне значення поля `base`
у файлі `vite.config.js`.

### Маршрутизація

Якщо додаток використовує бібліотеку `react-router-dom` для маршрутизації,
необхідно додатково налаштувати компонент `<BrowserRouter>`, передавши в пропе
`basename` точну назву твого репозиторію. Слеш на початку рядка обов'язковий.

```jsx
<BrowserRouter basename="/your_repo_name">
<App />
</BrowserRouter>
```
### Додавання змінних в .env
Для зберігання конфігураційних даних, таких як API ключі, адреси серверів, порти та інші змінні використовуйте файл `.env`. Для цього необхідно з назви файлу `.env.template` видалити зайві ".template",після чого файл відповідатиме умовам файлу `.ignore` і буде зберігатися лише локально, не публікуючись на віддаленому репозиторії з метою безпеки. Задля використання змінних на GitHub-pages усі змінні, передбачені файлом .env, слід додати до файлу `.github/workflows/deploy.yml`, а також до налаштувань репозиторію. Для цього слід перейти (`Settings` > `Secrets and variables` > `Actions`)

![Add enviroments from .env](./src/assets/secrets.png)

## Як це працює

1. Після кожного пушу в гілку `main` GitHub-репозиторію, запускається
спеціальний скрипт (GitHub Action) з файлу `.github/workflows/deploy.yml`.
2. Усі файли репозиторію копіюються на сервер, де проєкт ініціалізується і
проходить збірку перед деплоєм. 3 Якщо всі кроки пройшли успішно, зібрана
продакшн-версія файлів проєкту відправляється в гілку `gh-pages`. В іншому
випадку, в логах виконання скрипта буде вказано в чому проблема.
140 changes: 140 additions & 0 deletions authOperations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import axios from 'axios';
import { createAsyncThunk } from '@reduxjs/toolkit';
import {
signIn,
signOut,
getUser,
getRefreshToken,
updateBalance,
} from '../services';
import {
fetchIncomeCategories,
fetchExpenseCategories,
fetchIncome,
fetchExpense,
} from '../redux/transactionsOperations';
import { showErrorMessage } from '../components/Toasters';

const token = {
set(token) {
axios.defaults.headers.common.Authorization = `Bearer ${token}`;
},
unset() {
axios.defaults.headers.common.Authorization = '';
},
};

export const logIn = createAsyncThunk(
'auth/logIn',
async function (credentials, { rejectWithValue, dispatch }) {
try {
const { data } = await signIn(credentials);
token.set(data.accessToken);
sessionStorage.setItem('token', data.accessToken);
sessionStorage.setItem('refreshToken', data.refreshToken);
sessionStorage.setItem('sid', data.sid);
dispatch(fetchIncomeCategories());
dispatch(fetchExpenseCategories());
return data;
} catch (error) {
showErrorMessage(error.message);
return rejectWithValue(error.message);
}
},
);

export const logInGoogle = createAsyncThunk(
'auth/logIn',
async function (response, { rejectWithValue, dispatch }) {
try {
token.set(response.accessToken);
sessionStorage.setItem('token', response.accessToken);
sessionStorage.setItem('refreshToken', response.refreshToken);
sessionStorage.setItem('sid', response.sid);
await dispatch(getCurrentUser());
return response;
} catch (error) {
showErrorMessage(error.message);
return rejectWithValue(error.message);
}
},
);

export const logOut = createAsyncThunk(
'auth/logOut',
async function (_, { rejectWithValue, dispatch }) {
try {
sessionStorage.removeItem('token');
sessionStorage.removeItem('sid');
sessionStorage.removeItem('refreshToken');
await signOut();
token.unset();
} catch (error) {
showErrorMessage(error.message);
return rejectWithValue(error.message);
}
},
);

export const getCurrentUser = createAsyncThunk(
'auth/getCurrentUser',
async function (_, { rejectWithValue, dispatch }) {
try {
const accessToken = sessionStorage.getItem('token');
token.set(accessToken);
const response = await getUser();
if (response.data) {
dispatch(fetchIncome());
dispatch(fetchExpense());
}
return response.data;
} catch (error) {
showErrorMessage(error.message);
return rejectWithValue(error.message);
}
},
);
export const updateUserBalance = createAsyncThunk(
'auth/updateUserBalance',
async function (balance, { rejectWithValue, dispatch }) {
try {
const response = await updateBalance(balance);
return response.data;
} catch (error) {
showErrorMessage(error.message);
return rejectWithValue(error.message);
}
},
);

export const refresh = createAsyncThunk(
'auth/refresh',
async function (_, { rejectWithValue, dispatch, getState }) {
const sid = sessionStorage.getItem('sid');
const refreshToken = sessionStorage.getItem('refreshToken');
try {
const response = await getRefreshToken({ refreshToken, sid });
token.set(response.data.newAccessToken);
dispatch(getCurrentUser());
return response.data;
} catch (error) {
sessionStorage.removeItem('token');
sessionStorage.removeItem('sid');
sessionStorage.removeItem('refreshToken');
token.unset();
showErrorMessage(error.message);
return rejectWithValue(error.message);
}
},
);

const authOperations = {
logIn,
logInGoogle,
logOut,
getCurrentUser,
updateUserBalance,
refresh,
};

export default authOperations;
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
Loading

0 comments on commit 7c06d63

Please sign in to comment.