diff --git a/app/src/App.vue b/app/src/App.vue
index 30dd406..29abacf 100644
--- a/app/src/App.vue
+++ b/app/src/App.vue
@@ -6,4 +6,27 @@
diff --git a/app/src/common/EventBus.ts b/app/src/common/EventBus.ts
new file mode 100644
index 0000000..c0d5f9a
--- /dev/null
+++ b/app/src/common/EventBus.ts
@@ -0,0 +1,13 @@
+const eventBus = {
+ on(event: string, callback) {
+ document.addEventListener(event, (e) => callback(e.detail));
+ },
+ dispatch(event: string, data) {
+ document.dispatchEvent(new CustomEvent(event, { detail: data }));
+ },
+ remove(event: string, callback) {
+ document.removeEventListener(event, callback);
+ },
+};
+
+export default eventBus;
diff --git a/app/src/main.ts b/app/src/main.ts
index 1c2cc67..195347d 100644
--- a/app/src/main.ts
+++ b/app/src/main.ts
@@ -1,7 +1,7 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
-import Vuex from 'vuex'
+import setupInterceptors from './services/SetupInterceptors';
import { IonicVue } from '@ionic/vue';
@@ -37,6 +37,8 @@ import './theme/variables.css';
import store from './store';
+setupInterceptors(store);
+
const app = createApp(App)
.use(store)
.use(IonicVue)
diff --git a/app/src/services/Api.ts b/app/src/services/Api.ts
new file mode 100644
index 0000000..775a4f0
--- /dev/null
+++ b/app/src/services/Api.ts
@@ -0,0 +1,10 @@
+import axios from "axios";
+
+const instance = axios.create({
+ baseURL: "http://localhost:8080/api",
+ headers: {
+ "Content-Type": "application/json",
+ },
+});
+
+export default instance;
diff --git a/app/src/services/AuthService.ts b/app/src/services/AuthService.ts
index 0931541..6a6a036 100644
--- a/app/src/services/AuthService.ts
+++ b/app/src/services/AuthService.ts
@@ -1,17 +1,16 @@
-import axios from 'axios';
-
-const API_URL = 'http://localhost:8080/api/auth/';
+import api from './Api';
+import TokenService from './TokenService';
class AuthService {
public login(email: string, password: string) {
- return axios
- .post(API_URL + 'login', {
+ return api
+ .post('/auth/login', {
email,
password
})
.then(response => {
if (response.data.accessToken) {
- localStorage.setItem('user', JSON.stringify(response.data));
+ TokenService.setUser(response.data);
}
return response.data;
@@ -19,16 +18,15 @@ class AuthService {
}
public logout() {
- localStorage.removeItem('user');
+ TokenService.removeUser();
}
- public register(username: string, email: string, password: string) {
- return axios.post(API_URL + 'register', {
- username,
+ public register(email: string, password: string) {
+ return api.post('/auth/register', {
email,
password
});
}
}
-export default new AuthService();
\ No newline at end of file
+export default new AuthService();
diff --git a/app/src/services/PitchTypeService.ts b/app/src/services/PitchTypeService.ts
index 4bc348b..f0c3557 100644
--- a/app/src/services/PitchTypeService.ts
+++ b/app/src/services/PitchTypeService.ts
@@ -1,12 +1,5 @@
import PitchType from "@/types/PitchType";
-import axios, {AxiosInstance} from "axios";
-
-const apiClient: AxiosInstance = axios.create({
- baseURL: "http://localhost:8080/api",
- headers: {
- "Content-type": "application/json",
- },
-});
+import api from './Api';
class PitchTypeService {
private static instance: PitchTypeService;
@@ -22,12 +15,12 @@ class PitchTypeService {
}
async getAllPitchTypes(): Promise {
- const users = await apiClient.get('/pitch_types');
+ const users = await api.get('/pitch_types');
return users.data;
}
async getPitchType(id: number): Promise {
- const pitchType = await apiClient.get(`/pitch_types/${id}`);
+ const pitchType = await api.get(`/pitch_types/${id}`);
return pitchType.data;
// if (pitcher !== undefined) {
// return pitcher;
@@ -37,4 +30,4 @@ class PitchTypeService {
}
}
-export const pitchTypeService = PitchTypeService.getInstance();
\ No newline at end of file
+export const pitchTypeService = PitchTypeService.getInstance();
diff --git a/app/src/services/PitcherService.ts b/app/src/services/PitcherService.ts
index 186c694..87fa4fc 100644
--- a/app/src/services/PitcherService.ts
+++ b/app/src/services/PitcherService.ts
@@ -1,12 +1,6 @@
import Pitcher from "@/types/Pitcher";
-import axios, { AxiosInstance } from "axios";
+import api from './Api';
-const apiClient: AxiosInstance = axios.create({
- baseURL: "http://localhost:8080/api",
- headers: {
- "Content-type": "application/json",
- },
-});
class PitcherService {
private static instance: PitcherService;
@@ -21,12 +15,12 @@ class PitcherService {
}
async getAllPitchers(): Promise {
- const users = await apiClient.get('/users');
+ const users = await api.get('/users');
return users.data;
}
async getPitcher(id: number): Promise {
- const pitcher = await apiClient.get(`/users/${id}`);
+ const pitcher = await api.get(`/users/${id}`);
return pitcher.data;
// const pitcher = pitchers.get(id);
// if (pitcher !== undefined) {
@@ -37,4 +31,4 @@ class PitcherService {
}
}
-export const pitcherService = PitcherService.getInstance();
\ No newline at end of file
+export const pitcherService = PitcherService.getInstance();
diff --git a/app/src/services/SetupInterceptors.ts b/app/src/services/SetupInterceptors.ts
new file mode 100644
index 0000000..fd8efef
--- /dev/null
+++ b/app/src/services/SetupInterceptors.ts
@@ -0,0 +1,55 @@
+import axiosInstance from "./Api";
+import TokenService from "./TokenService";
+import { Store } from 'vuex';
+import {RootState} from '@/store';
+
+const setup = (store: Store) => {
+ axiosInstance.interceptors.request.use(
+ (config) => {
+ const token = TokenService.getLocalAccessToken();
+ if (token) {
+ // config.headers["Authorization"] = 'Bearer ' + token; // for Spring Boot back-end
+ config.headers["x-access-token"] = token; // for Node.js Express back-end
+ }
+ return config;
+ },
+ (error) => {
+ return Promise.reject(error);
+ }
+ );
+
+ axiosInstance.interceptors.response.use(
+ (res) => {
+ return res;
+ },
+ async (err) => {
+ const originalConfig = err.config;
+
+ if (originalConfig.url !== "/auth/login" && err.response) {
+ // Access Token was expired
+ if (err.response.status === 401 && !originalConfig._retry) {
+ originalConfig._retry = true;
+
+ try {
+ const rs = await axiosInstance.post("/auth/refreshtoken", {
+ refreshToken: TokenService.getLocalRefreshToken(),
+ });
+
+ const { accessToken } = rs.data;
+
+ await store.dispatch('auth/refreshToken', accessToken);
+ TokenService.updateLocalAccessToken(accessToken);
+
+ return axiosInstance(originalConfig);
+ } catch (_error) {
+ return Promise.reject(_error);
+ }
+ }
+ }
+
+ return Promise.reject(err);
+ }
+ );
+};
+
+export default setup;
diff --git a/app/src/services/TokenService.ts b/app/src/services/TokenService.ts
new file mode 100644
index 0000000..bd2c013
--- /dev/null
+++ b/app/src/services/TokenService.ts
@@ -0,0 +1,34 @@
+import UserInfo from '@/types/UserInfo';
+
+class TokenService {
+ getLocalRefreshToken() {
+ const user = JSON.parse(localStorage.getItem("user") || '""');
+ return user?.refreshToken;
+ }
+
+ getLocalAccessToken() {
+ const user = JSON.parse(localStorage.getItem("user")|| '""');
+ return user?.accessToken;
+ }
+
+ updateLocalAccessToken(token: string) {
+ const user: UserInfo = JSON.parse(localStorage.getItem("user")|| '""');
+ user.accessToken = token;
+ localStorage.setItem("user", JSON.stringify(user));
+ }
+
+ getUser() {
+ return JSON.parse(localStorage.getItem("user")|| '""');
+ }
+
+ setUser(user: UserInfo) {
+ console.log(JSON.stringify(user));
+ localStorage.setItem("user", JSON.stringify(user));
+ }
+
+ removeUser() {
+ localStorage.removeItem("user");
+ }
+}
+
+export default new TokenService();
diff --git a/app/src/types/UserInfo.ts b/app/src/types/UserInfo.ts
new file mode 100644
index 0000000..55cac7f
--- /dev/null
+++ b/app/src/types/UserInfo.ts
@@ -0,0 +1,7 @@
+export default interface UserInfo {
+ id: number,
+ email: string,
+ roles: string[],
+ accessToken: string,
+ refreshToken: string
+}