Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4주차 기본/심화/생각 과제] 로그인 🔑 회원가입 👤 #4

Merged
merged 52 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
176b173
practice : 👊🏻 4차 세미나 실습
binllionaire Nov 11, 2023
719ab17
init : 🎉 Vite + React 환경 세팅
binllionaire Nov 14, 2023
9a46bfc
add : 📦 styled-components 라이브러리 추가
binllionaire Nov 14, 2023
22f326e
add : 📦 react-router-dom 라이브러리 추가
binllionaire Nov 14, 2023
cad65d6
design : 💄 전역 스타일 적용
binllionaire Nov 14, 2023
92111ba
feat : ✨ 라우트 설정
binllionaire Nov 14, 2023
561823f
add : 🍱 Pretendard 폰트 추가
binllionaire Nov 14, 2023
c1666fd
add : 🍱 아이콘 추가
binllionaire Nov 14, 2023
9ea2195
remove : 🔥 사용하지 않는 파일 제거
binllionaire Nov 14, 2023
f295b35
design : 💄 ThemeProvider 설정
binllionaire Nov 14, 2023
be3d429
design : 💄 로그인 페이지 퍼블리싱
binllionaire Nov 14, 2023
771b700
refactor : ♻️ 스타일 컴포넌트 분리
binllionaire Nov 14, 2023
1745ecb
design : 💄 회원가입 페이지 퍼블리싱
binllionaire Nov 14, 2023
22aedad
refactor : ♻️ SignForm 컴포넌트 분리
binllionaire Nov 14, 2023
bed381e
design : 💄 닉네임 필드 추가
binllionaire Nov 14, 2023
fcf96dd
fix : ✏️ 로그인 -> 아이디 오타 수정
binllionaire Nov 14, 2023
88a0a0c
add : 🍱 프로필 이미지 추가
binllionaire Nov 14, 2023
48779de
design : 💄 마이페이지 퍼블리싱
binllionaire Nov 14, 2023
f0a2695
design : 💄 유저 정보 텍스트 스타일 수정
binllionaire Nov 14, 2023
2c571a4
feat : ✨ 회원가입 페이지 이동 구현
binllionaire Nov 14, 2023
08db495
add : 📦 axios 라이브러리 추가
binllionaire Nov 14, 2023
9b71f86
feat : ✨ 아이디 중복 체크 구현
binllionaire Nov 14, 2023
8c09b5b
design : 💄 Theme 색상 추가
binllionaire Nov 14, 2023
c1e069b
design : 💄 활성화/비활성화 버튼
binllionaire Nov 14, 2023
b983bd8
feat : ✨ 회원가입 버튼 활성화 구현
binllionaire Nov 14, 2023
c298ba2
feat : ✨ 회원가입 구현
binllionaire Nov 14, 2023
396e1a5
rename : 🚚 상수명 변경
binllionaire Nov 14, 2023
a5238a2
style : 🎨 import문 개행 수정
binllionaire Nov 14, 2023
16137a9
add : 🍱 파비콘 이미지 추가
binllionaire Nov 14, 2023
a4926e1
improve : ♿ 언어, 파비콘, 타이틀 수정
binllionaire Nov 14, 2023
d8d8d4c
remove : 🔥 사용하지 않는 이미지 파일 삭제
binllionaire Nov 14, 2023
c3ce5b6
feat : ✨ 로그인 구현
binllionaire Nov 14, 2023
78227d9
feat : ✨ 마이페이지 구현
binllionaire Nov 14, 2023
1fff37a
feat : ✨ 로그아웃 구현
binllionaire Nov 14, 2023
1ac9792
refactor : ♻️ 유저 정보 서버 통신 로직 분리
binllionaire Nov 14, 2023
c4e9af4
refactor : ♻️ 중복 체크 플래그 상수화
binllionaire Nov 14, 2023
4be8d51
feat : ✨ 토스트 메시지 구현
binllionaire Nov 15, 2023
6a345d2
move : 🚚 컴포넌트 해당 페이지 별로 폴더화
binllionaire Nov 15, 2023
558885e
docs : 📝 생각과제 작성
binllionaire Nov 16, 2023
e3190e0
refactor : ♻️ 타이틀 컴포넌트 분리
binllionaire Nov 16, 2023
533af69
refactor : ♻️ 회원가입 이동 텍스트 컴포넌트 분리
binllionaire Nov 16, 2023
cbf0217
refactor : ♻️ createPortal 로직 이동
binllionaire Nov 16, 2023
b479edb
fix : 🚑️ 토스트 에러 메시지 변경
binllionaire Nov 16, 2023
d750dc7
move : 🚚 토스트 컴포넌트 이동
binllionaire Nov 16, 2023
981afe3
style : 🎨 import문 개행 수정
binllionaire Nov 16, 2023
6812b80
refactor : ♻️ 중복체크 플래그 상수 사용
binllionaire Nov 16, 2023
cdc5b0a
fix : 💬 비밀번호 확인 placeholder 텍스트 수정
binllionaire Nov 16, 2023
b990e3f
fix : 🔒 서버 URL .env로 설정
binllionaire Nov 16, 2023
9b7bfbb
add : 🙈 .env 반영되지 않도록 추가
binllionaire Nov 16, 2023
fe89bf7
refactor : ♻️ 중복체크 플래그 상수 사용
binllionaire Nov 17, 2023
c743b75
design : 💄 회원가입 버튼 활성화 시 커서 변경
binllionaire Nov 17, 2023
d8c9600
move : 🚚 week2,week3 -> week4
binllionaire Nov 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
477 changes: 477 additions & 0 deletions week2/assignment/가계부 💸/index.css

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions week2/assignment/가계부 💸/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="ko">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="index.css" />
<link rel="shortcut icon" href="./assets/img/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>수빈 | 가계부</title>
</head>

<body>
<header>
<h1>수빈이의 가계부</h1>
</header>
<section id="asset">
<h2 class="subtitle">나의 자산</h2>
<b id="money" class="money"></b>
<div id="today">
<img src="./assets/img/triangle-up.png" alt="위쪽화살표" />
<p class="income money"></p>
<img src="./assets/img/triangle-down.png" alt="아래쪽화살표" />
<p class="spending money"></p>
</div>
</section>
<section id="main">
<h2 class="subtitle">내역 리스트</h2>
<div id="date">
<button type="button" id="prev-day">▸</button>
<p>10월 9일</p>
<button type="button" id="next-day">▸</button>
</div>
<div id="money-type">
<input type="checkbox" id="type-income" checked />
<label for="type-income">수입</label>
<input type="checkbox" id="type-spending" checked />
<label for="type-spending">지출</label>
</div>
<div id="history">
<ul>

</ul>
</div>
</section>
<footer>
<button type="button" id="add">내역 추가</button>
<a href="pages/category.html" id="manage-category">카테고리</a>
</footer>
<section>
<div id="modal-background">

</div>
<div id="add-history-modal">
<h2>내역추가</h2>
<div id="type-selector">
<input type="radio" id="select-income" name="transaction-type" checked />
<label for="select-income">수입</label>
<input type="radio" id="select-spending" name="transaction-type" />
<label for="select-spending">지출</label>
</div>
<div id="category-selector">
<p>카테고리</p>
<div class="select-category">
<div class="selector">
<p class="selected-category">카테고리를 선택하세요</p>
<button type="button" class="drop-down">▾</button>
</div>
<ul class="categories">

</ul>
</div>
</div>
<div id="price-input">
<p>금액</p>
<input type="text" id="input-price" placeholder="금액을 입력하세요" />
</div>
<div id="content-input">
<p>내용</p>
<input type="text" id="input-content" placeholder="지출처를 입력하세요" />
</div>
<div id="modal-button-wrapper">
<button type="button" id="close">닫기</button>
<button type="button" id="save">저장하기</button>
</div>
</div>
</section>
<section>
<div id="modal-background">

</div>
<div id="delete-modal">
<p>정말 삭제하시겠습니까?</p>
<div id="modal-button-wrapper">
<button type="button" id="confirm">네</button>
<button type="button" id="cancel">아니요</button>
</div>
</div>
</section>
<script type="module" src="index.js"></script>
<script type="module" src="js/History/transactionFilter.js"></script>
</body>

</html>
11 changes: 11 additions & 0 deletions week2/assignment/가계부 💸/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { renderHistoryList } from "./js/History/HistoryView.js";
import { renderAssetData } from "./js/Asset/AssetView.js";
import { renderCategory } from "./js/Category/CategoryView.js";

function render() {
renderHistoryList();
renderAssetData();
renderCategory();
}

render();
55 changes: 55 additions & 0 deletions week2/assignment/가계부 💸/js/Asset/AssetView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {
HISTORY_LIST,
INIT_BALANCE,
INIT_INCOME,
INIT_SPENDING,
TRANSACTION_TYPE,
} from "../utils/constants.js";

import {
TODY_TOTAL_INCOME,
TODY_TOTAL_SPENDING,
TOTAL_MONEY,
} from "../utils/documentElements.js";

import { changeFormat } from "../utils/moneyFormatter.js";

let total;
let income;
let spending;

function resetMoney() {
total = INIT_BALANCE;
income = INIT_INCOME;
spending = INIT_SPENDING;
}

function calculateMoney(history) {
switch (history.type) {
case TRANSACTION_TYPE.SPENDING:
total -= history.money;
spending += history.money;
break;
case TRANSACTION_TYPE.INCOME:
total += history.money;
income += history.money;
break;
default:
break;
}
}

function setMoney() {
TOTAL_MONEY.innerHTML = total;
TODY_TOTAL_INCOME.innerHTML = income;
TODY_TOTAL_SPENDING.innerHTML = spending;
}

export function renderAssetData() {
resetMoney();
HISTORY_LIST.forEach((history) => {
calculateMoney(history);
});
setMoney();
changeFormat();
}
70 changes: 70 additions & 0 deletions week2/assignment/가계부 💸/js/Category/CategoryController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { CATEGORY, ELEMENT, LOCAL_STORAGE, TRANSACTION_TYPE } from "../utils/constants.js";
import {
HOME_BUTTON,
INCOME_CATEGORY_INPUT,
INCOME_CATEGORY_SECTION,
SPENDING_CATEGORY_INPUT,
SPENDING_CATEGORY_SECTION,
} from "../utils/documentElements.js";

HOME_BUTTON.addEventListener("click", () => {
window.location.href = "../index.html";
});

function addToCategoryList(type, name) {
const categoryList =
type === TRANSACTION_TYPE.INCOME ? CATEGORY.INCOME : CATEGORY.SPENDING;
categoryList.push(name);
}

function appendCategoryTagElement(name, categorySection) {
const CATEGORY_TAG = document.createElement(ELEMENT.HTMLTAG.DIV);
CATEGORY_TAG.className = ELEMENT.CLASSNAME.CATEGORY_TAG;
CATEGORY_TAG.innerHTML = name;
categorySection.appendChild(CATEGORY_TAG);
}

function saveToLocalStorage(type) {
const storageKey =
type === TRANSACTION_TYPE.INCOME
? LOCAL_STORAGE.INCOME
: LOCAL_STORAGE.SPENDING;
const categoryList =
type === TRANSACTION_TYPE.INCOME ? CATEGORY.INCOME : CATEGORY.SPENDING;
localStorage.setItem(storageKey, JSON.stringify(categoryList));
}

function handleCategoryInput(type, inputField, categorySection) {
inputField.addEventListener("keydown", (event) => {
if (event.isComposing) return; // 중복 입력 방지
if (event.key === "Enter") {
const categoryName = event.target.value;
addToCategoryList(type, categoryName);
appendCategoryTagElement(categoryName, categorySection);
saveToLocalStorage(type);
inputField.value = "";
}
});
}

function renderCategoryTag(type, categorySection) {
const categoryList =
type === TRANSACTION_TYPE.INCOME ? CATEGORY.INCOME : CATEGORY.SPENDING;
categoryList.forEach((category) => {
appendCategoryTagElement(category, categorySection);
});
}

renderCategoryTag(TRANSACTION_TYPE.INCOME, INCOME_CATEGORY_SECTION);
renderCategoryTag(TRANSACTION_TYPE.SPENDING, SPENDING_CATEGORY_SECTION);

handleCategoryInput(
TRANSACTION_TYPE.INCOME,
INCOME_CATEGORY_INPUT,
INCOME_CATEGORY_SECTION
);
handleCategoryInput(
TRANSACTION_TYPE.SPENDING,
SPENDING_CATEGORY_INPUT,
SPENDING_CATEGORY_SECTION
);
60 changes: 60 additions & 0 deletions week2/assignment/가계부 💸/js/Category/CategoryView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { CATEGORY, ELEMENT, TRANSACTION_TYPE } from "../utils/constants.js";
import {
DROP_DOWN_CATEGORIES,
SELECTED_CATEGORY,
SELECTOR_DIV,
SELECT_TYPE_INCOME,
SELECT_TYPE_SPENDING,
} from "../utils/documentElements.js";

function handleSelectChange() {
SELECT_TYPE_INCOME.addEventListener("change", () => {
renderCategory(TRANSACTION_TYPE.INCOME, CATEGORY.INCOME);
SELECTED_CATEGORY.innerText = CATEGORY.INCOME[0];
});

SELECT_TYPE_SPENDING.addEventListener("change", () => {
renderCategory(TRANSACTION_TYPE.SPENDING, CATEGORY.SPENDING);
SELECTED_CATEGORY.innerText = CATEGORY.SPENDING[0];
});
}

function handleCategoryClick() {
const categories = document.querySelectorAll(".categories .category");
categories.forEach((category) => {
category.addEventListener("click", (event) => {
SELECTED_CATEGORY.innerText = event.target.innerText;
SELECTOR_DIV.classList.remove(ELEMENT.CLASSNAME.ACTIVE);
});
});
}

function createCategoryList(type, category) {
const dropDownList = document.createElement(ELEMENT.HTMLTAG.LIST);
dropDownList.className = ELEMENT.CLASSNAME.CATEGORY;
type === TRANSACTION_TYPE.INCOME
? dropDownList.classList.add(ELEMENT.CLASSNAME.TYPE_INCOME)
: dropDownList.classList.add(ELEMENT.CLASSNAME.TYPE_SPENDING);
dropDownList.innerHTML = category;
DROP_DOWN_CATEGORIES.appendChild(dropDownList);
handleCategoryClick();
}

function resetCategory() {
while (DROP_DOWN_CATEGORIES.firstChild) {
DROP_DOWN_CATEGORIES.removeChild(DROP_DOWN_CATEGORIES.firstChild);
}
}

export function renderCategory(type, categoryList) {
if (!type & !categoryList) {
type = TRANSACTION_TYPE;
categoryList = CATEGORY.INCOME;
handleCategoryClick();
}
resetCategory();
categoryList.forEach((category) => {
createCategoryList(type, category);
});
handleSelectChange();
}
55 changes: 55 additions & 0 deletions week2/assignment/가계부 💸/js/History/HistoryController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { renderAssetData } from "../Asset/AssetView.js";
import { ELEMENT, HISTORY_LIST } from "../utils/constants.js";
import { MODAL_BACKGROUND, CANCEL_BUTTON, CONFIRM_BUTTON, MODAL_DELETE } from "../utils/documentElements.js";

let indexToDelete;
let listToDelete;
let isConfirmed = false;

function findIndexToDelete() {
return HISTORY_LIST.findIndex((history) => indexToDelete === history.id);
}

function deleteList() {
const index = findIndexToDelete();
if (index !== -1) {
HISTORY_LIST.splice(index, 1);
listToDelete.remove();
renderAssetData();
}
}

function handleConfirmClick() {
isConfirmed = true;
deleteList();
closeModal();
}

function handleCancelClick() {
isConfirmed = false;
closeModal();
}

function openModal() {
MODAL_DELETE.style.display = ELEMENT.STYLE.DISPLAY.FLEX;
MODAL_BACKGROUND.style.display = ELEMENT.STYLE.DISPLAY.BLOCK;
}

function closeModal() {
MODAL_DELETE.style.display = ELEMENT.STYLE.DISPLAY.NONE;
MODAL_BACKGROUND.style.display = ELEMENT.STYLE.DISPLAY.NONE;
}

export function setDeleteEvent() {
const deleteButtons = document.querySelectorAll("button.delete");
deleteButtons.forEach((button) => {
button.addEventListener("click", (event) => {
indexToDelete = parseInt(event.target.getAttribute(ELEMENT.ATTRIBUTE.DATA_INDEX));
listToDelete = event.target.parentElement;
openModal();
});
});

CONFIRM_BUTTON.addEventListener("click", handleConfirmClick);
CANCEL_BUTTON.addEventListener("click", handleCancelClick);
}
37 changes: 37 additions & 0 deletions week2/assignment/가계부 💸/js/History/HistoryListTemplate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { TRANSACTION_TYPE, ELEMENT } from "../utils/constants.js";

export function makeCategoryElement(category) {
const historyCategory = document.createElement(ELEMENT.HTMLTAG.TEXT);
historyCategory.className = ELEMENT.CLASSNAME.CATEGORY;
historyCategory.innerHTML = category;
return historyCategory;
}

export function makeNameElement(name) {
const historyName = document.createElement(ELEMENT.HTMLTAG.TEXT);
historyName.className = ELEMENT.CLASSNAME.NAME;
historyName.innerHTML = name;
return historyName;
}

export function makePriceElement(type, price) {
const historyPrice = document.createElement(ELEMENT.HTMLTAG.TEXT);
historyPrice.className = ELEMENT.CLASSNAME.PRICE;
if (type === TRANSACTION_TYPE.SPENDING) {
historyPrice.classList.add(ELEMENT.CLASSNAME.SPENDING, ELEMENT.CLASSNAME.MONEY);
}
if (type === TRANSACTION_TYPE.INCOME) {
historyPrice.classList.add(ELEMENT.CLASSNAME.INCOME, ELEMENT.CLASSNAME.MONEY);
}
historyPrice.innerText = price;
return historyPrice;
}

export function makeDeleteButton(id) {
const deleteButton = document.createElement(ELEMENT.HTMLTAG.BUTTON);
deleteButton.className = ELEMENT.CLASSNAME.DELETE;
const attributeName = ELEMENT.ATTRIBUTE.DATA_INDEX;
const attributeValue = id;
deleteButton.setAttribute(attributeName, attributeValue);
return deleteButton;
}
Loading