diff --git a/src/assets/scss/auth/auth.scss b/src/assets/scss/auth/auth.scss index 0a54d85..07bb959 100644 --- a/src/assets/scss/auth/auth.scss +++ b/src/assets/scss/auth/auth.scss @@ -3,29 +3,69 @@ h1 { } .login-form { - @include flex-box(column, center, 60px); - width: 400px; + @include flex-box(column, center, 50px); + width: 500px; + margin: 0 30px; .input-box { @include flex-box(column, center, 20px); width: 100%; } - .button-box { +} + +.signup-form { + @include flex-box(column, center, 50px); + width: 700px; + margin: 0 30px; + .signup-grid { + @include flex-box(row, center, 50px); + width: 100%; + } + .input-left { @include flex-box(column, center, 20px); + width: 60%; + } + .input-right { + @include flex-box(column, center, 20px); + width: 40%; + } + +} + +.input-item { + width: 100%; +} + +.button-box { + @include flex-box(column, center, 20px); + width: 100%; + .guide-line { width: 100%; - .guide-line { - width: 100%; - @include flex-box(row, space-between, 0px); - font-size: 14px; - font-weight: bold; - span { - cursor: pointer; - transition: all 0.5s; - &:hover { - color: black; - } + @include flex-box(row, space-between, 0px); + font-size: 14px; + font-weight: bold; + span { + cursor: pointer; + transition: all 0.5s; + &:hover { + opacity: 0.5; } } } } +.warning-msg { + color: #ff6347; + font-size: 13px; + font-weight: bold; + text-align: left; + height: 15px; +} + +.valid-msg { + color: #3CB371; + font-size: 13px; + font-weight: bold; + text-align: left; + height: 15px; +} diff --git a/src/assets/scss/common.scss b/src/assets/scss/common.scss index 8c66379..4d36f11 100644 --- a/src/assets/scss/common.scss +++ b/src/assets/scss/common.scss @@ -15,19 +15,40 @@ $side-bar-width : 150px; gap: $gap; } -@mixin base-button { - width: 100%; +@mixin base-button($width, $font-size) { + width: $width; box-shadow: 0 5px 10px rgba(0,0,0,0.16), 0 5px 10px rgba(0,0,0,0.23); box-sizing: border-box; padding: 10px; - border-radius: 15px; - font-size: 18px; + border-radius: 10px; + font-size: $font-size; font-weight: bold; - cursor: pointer; transition: all 0.3s cubic-bezier(.25,.8,.25,1); + cursor: pointer; &:hover { box-shadow: 0 1px 2px rgba(0,0,0,0.25), 0 1px 2px rgba(0,0,0,0.22); } + &:active { + opacity: 0.7; + } +} + +@mixin base-input($width, $font-size) { + box-sizing: border-box; + width: $width; + font-size: $font-size; + font-weight: bold; + padding: 12px 20px; + border: none ; + border-radius: 5px; + box-shadow: 0px 1px 4px 1px rgb(0, 0, 0, 0.20); + transition: all 0.3s; + &:focus { + outline: none; + box-shadow: 0px 1px 5px 1px rgb(0, 0, 0, 0.5); + } } + + diff --git a/src/components/auth/AuthBtnInput.vue b/src/components/auth/AuthBtnInput.vue new file mode 100644 index 0000000..09053ab --- /dev/null +++ b/src/components/auth/AuthBtnInput.vue @@ -0,0 +1,50 @@ + + + + + \ No newline at end of file diff --git a/src/components/auth/AuthButton.vue b/src/components/auth/AuthButton.vue index b7d660d..ff48ea7 100644 --- a/src/components/auth/AuthButton.vue +++ b/src/components/auth/AuthButton.vue @@ -14,7 +14,9 @@ export default { \ No newline at end of file diff --git a/src/components/common/NavBar.vue b/src/components/common/TheNavBar.vue similarity index 64% rename from src/components/common/NavBar.vue rename to src/components/common/TheNavBar.vue index f707702..c09af11 100644 --- a/src/components/common/NavBar.vue +++ b/src/components/common/TheNavBar.vue @@ -2,20 +2,29 @@ diff --git a/src/components/common/SideBar.vue b/src/components/common/TheSideBar.vue similarity index 98% rename from src/components/common/SideBar.vue rename to src/components/common/TheSideBar.vue index 97ac713..5484bcf 100644 --- a/src/components/common/SideBar.vue +++ b/src/components/common/TheSideBar.vue @@ -17,7 +17,7 @@ import SideBarItemVue from './side-bar/SideBarItem.vue'; import SideBarLogoutVue from './side-bar/SideBarLogout.vue'; export default { - name: 'SideBarVue', + name: 'TheSideBarVue', components: { SideBarLogoutVue, SideBarItemVue diff --git a/src/components/common/side-bar/SideBarLogout.vue b/src/components/common/side-bar/SideBarLogout.vue index ebe0563..84a4c34 100644 --- a/src/components/common/side-bar/SideBarLogout.vue +++ b/src/components/common/side-bar/SideBarLogout.vue @@ -14,9 +14,8 @@ export default { ...mapStores(useAuthStore) }, methods: { - logout() { - this.authStore.logout(); - this.$router.push({ name: 'login' }); + async logout() { + await this.authStore.logout(); } } } diff --git a/src/router/index.js b/src/router/index.js index 60433e0..fb20a5c 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -57,11 +57,6 @@ const router = createRouter({ name: 'login', component: () => import('@/views/auth/LoginView.vue'), }, - { - path: '/cetify', - name: 'certify', - component: () => import('@/views/auth/CertifyView.vue'), - }, { path: '/signup', name: 'signup', diff --git a/src/stores/auth.js b/src/stores/auth.js index 429d58f..d71b8f5 100644 --- a/src/stores/auth.js +++ b/src/stores/auth.js @@ -1,3 +1,5 @@ +import router from '@/router'; +import { authAxios } from '@/utils/axios'; import { defineStore } from 'pinia' export const useAuthStore = defineStore('auth', { @@ -8,10 +10,12 @@ export const useAuthStore = defineStore('auth', { }, actions: { login() { - this.isLoggedIn = true + this.isLoggedIn = true; }, logout() { - this.isLoggedIn = false + authAxios.post('auth/logout'); + this.isLoggedIn = false; + router.push({name: 'login'}) } }, persist: { diff --git a/src/stores/signup.js b/src/stores/signup.js new file mode 100644 index 0000000..7d720ea --- /dev/null +++ b/src/stores/signup.js @@ -0,0 +1,30 @@ +import { defineStore } from 'pinia' + +export const useAuthStore = defineStore('signup', { + state() { + return { + email: '', + phone: '', + password: '', + name: '', + authCode: '', + } + }, + actions: { + login() { + this.isLoggedIn = true + }, + logout() { + this.isLoggedIn = false + } + }, + persist: { + enabled: true, + strategies: [ + { + storage: sessionStorage, + paths: ['isLoggedIn'] + } + ] + } +}) \ No newline at end of file diff --git a/src/utils/auth.js b/src/utils/auth.js new file mode 100644 index 0000000..498f9a6 --- /dev/null +++ b/src/utils/auth.js @@ -0,0 +1,37 @@ +// 입력값 클래스 +class InputValue { + constructor(value = '', isValid = false, errorMsg = '') { + this.value = value; + this.isValid = isValid; + this.errorMsg = errorMsg; + } +} + +// 타이머 클래스 +class ValidationTimer { + constructor(Inputvalue) { + this.inputValue = Inputvalue; + this.timeLeft = null; + this.interval = null; + } + + startTimer(onTimerEnd) { + if (this.interval) { + clearInterval(this.interval); + } + + this.timeLeft = 180; + this.interval = setInterval(() => { + this.timeLeft--; + this.inputValue.errorMsg = `남은 시간 : ${this.timeLeft}초`; + if (this.timeLeft <= 0) { + clearInterval(this.interval); + onTimerEnd(); + this.inputValue.errorMsg = `입력 시간 초과`; + } + }, 1000); + } +} + + +export { InputValue, ValidationTimer } \ No newline at end of file diff --git a/src/utils/axios.js b/src/utils/axios.js index 43c7413..7374bae 100644 --- a/src/utils/axios.js +++ b/src/utils/axios.js @@ -1,10 +1,51 @@ +import { useAuthStore } from '@/stores/auth'; import axios from 'axios'; +// 인증, 인가 관련 API const authAxios = axios.create({ - baseURL: `${import.meta.env.VITE_API_URL}/auth`, - headers: { - 'Content-Type': 'application/json', - }, + baseURL: `${import.meta.env.VITE_API_URL}`, + headers: { + 'Content-Type': 'application/json', + }, + withCredentials: true }); -export { authAxios } \ No newline at end of file +authAxios.interceptors.response.use( + (response) => { + return response.data; + }, + (error) => { + return error.response.data; + } +); + +// 일반 API +const mainAxios = axios.create({ + baseURL: `${import.meta.env.VITE_API_URL}`, + headers: { + 'Content-Type': 'application/json', + }, + withCredentials: true +}) + +mainAxios.interceptors.response.use( + (response) => { + return response.data; + }, + async (error) => { + // 잘못된 토큰 + if (error.response.data.code === 401) { + const authStore = useAuthStore(); + authStore.logout(); + // 만료된 엑세스 토큰 + } else if (error.response.data.code === 419) { + await mainAxios.post('auth/reissue') + return await mainAxios(error.config); + // 그 외의 예외 + } else { + return error.response.data; + } + } +); + +export { authAxios, mainAxios } \ No newline at end of file diff --git a/src/views/MainView.vue b/src/views/MainView.vue index 4ac6c83..eef3505 100644 --- a/src/views/MainView.vue +++ b/src/views/MainView.vue @@ -1,7 +1,7 @@ diff --git a/src/views/auth/CertifyView.vue b/src/views/auth/CertifyView.vue deleted file mode 100644 index 68a456d..0000000 --- a/src/views/auth/CertifyView.vue +++ /dev/null @@ -1,40 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/views/auth/LoginView.vue b/src/views/auth/LoginView.vue index 8ec4a46..a9d3967 100644 --- a/src/views/auth/LoginView.vue +++ b/src/views/auth/LoginView.vue @@ -1,18 +1,19 @@ \ No newline at end of file diff --git a/src/views/auth/SignupView.vue b/src/views/auth/SignupView.vue index 05abb2f..1c99db2 100644 --- a/src/views/auth/SignupView.vue +++ b/src/views/auth/SignupView.vue @@ -1,42 +1,252 @@ \ No newline at end of file