+
@@ -53,18 +49,14 @@
+
+
diff --git a/ui/src/pages/StravaLoginPage.vue b/ui/src/pages/StravaLoginPage.vue
new file mode 100644
index 0000000..550fdbf
--- /dev/null
+++ b/ui/src/pages/StravaLoginPage.vue
@@ -0,0 +1,94 @@
+
+
+
+ Strava Login
+
+
+
+ To log in, please click the "Login with Strava" button below. Once
+ the login process is complete, Strava will redirect you back to our
+ application.
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/router/index.js b/ui/src/router/index.js
index 30afb20..d398f65 100644
--- a/ui/src/router/index.js
+++ b/ui/src/router/index.js
@@ -1,27 +1,64 @@
import { createRouter, createWebHistory } from 'vue-router';
-import Cookies from 'js-cookie';
-import LoginPage from '@/pages/LoginPage';
+import StravaLoginPage from '@/pages/StravaLoginPage';
import HomePage from '@/pages/HomePage';
import SettingsPage from '@/pages/SettingsPage';
import DashboardDetail from '@/pages/DashboardDetail';
import AthletesPage from '@/pages/AthletesPage';
import ActivitiesPage from '@/pages/ActivitiesPage';
import GearsPage from '@/pages/GearsPage';
+import SetupPage from '@/pages/SetupPage';
+import LoginPage from '@/pages/LoginPage';
+import { useStravaStore } from '@/store/strava';
import { useUserStore } from '@/store/user';
-import { getUserMe } from '@/services/user';
+import { getStravaUser } from '@/services/user';
+import { checkSetupCompleted, getUserConfig } from '@/services/config';
const routes = [
- { path: '/', name: 'Home', component: HomePage },
+ {
+ path: '/',
+ name: 'Home',
+ component: HomePage,
+ },
{
path: '/app/dashboard/:id',
name: 'DashboardDetail',
component: DashboardDetail,
},
- { path: '/app/login', name: 'Login', component: LoginPage },
- { path: '/app/settings', name: 'Settings', component: SettingsPage },
- { path: '/app/activities', name: 'Activities', component: ActivitiesPage },
- { path: '/app/athletes', name: 'Athletes', component: AthletesPage },
- { path: '/app/gears', name: 'Gears', component: GearsPage },
+ {
+ path: '/app/strava-login',
+ name: 'StravaLogin',
+ component: StravaLoginPage,
+ },
+ {
+ path: '/app/settings',
+ name: 'Settings',
+ component: SettingsPage,
+ },
+ {
+ path: '/app/activities',
+ name: 'Activities',
+ component: ActivitiesPage,
+ },
+ {
+ path: '/app/athletes',
+ name: 'Athletes',
+ component: AthletesPage,
+ },
+ {
+ path: '/app/gears',
+ name: 'Gears',
+ component: GearsPage,
+ },
+ {
+ path: '/app/setup',
+ name: 'Setup',
+ component: SetupPage,
+ },
+ {
+ path: '/app/login',
+ name: 'Login',
+ component: LoginPage,
+ },
];
const router = createRouter({
@@ -31,16 +68,66 @@ const router = createRouter({
router.beforeEach(async (to, from, next) => {
const userStore = useUserStore();
- const accessToken = Cookies.get('accessToken');
+ const stravaStore = useStravaStore();
+ const stravaToken = stravaStore.getAccessToken();
+ const accessToken = userStore.getAccessToken();
+
+ // Check if the setup is completed
+ if (!userStore.setupCompleted) {
+ const resp = await checkSetupCompleted();
+ userStore.setSetupCompleted(resp.login_type, resp.completed);
- if (userStore.accessToken === '' && accessToken) {
+ // If setup is not completed and the target page is not 'Setup', redirect to 'Setup' page
+ if (!resp.completed && to.name !== 'Setup') {
+ return next({ name: 'Setup' });
+ }
+ }
+
+ // Authentication Check
+ const loginNeeded = userStore.loginNeeded();
+
+ if (!loginNeeded) {
+ const resp = await getUserConfig("");
+ userStore.setConfig(resp);
+ } else if (!userStore.isAuthenticated() && accessToken) {
try {
- const resp = await getUserMe(accessToken);
- userStore.setUser(accessToken, resp.athlete);
+ const resp = await getUserConfig(accessToken);
+ userStore.login(resp, accessToken);
} catch {
userStore.logout();
}
}
+
+ // If login is needed and the user is not authenticated, redirect to 'Login' page
+ if (loginNeeded && !userStore.isAuthenticated() && to.name !== 'Login') {
+ return next({ name: 'Login' });
+ }
+
+ // Strava Token management
+ if (!stravaStore.isAuthenticated() && stravaToken) {
+ try {
+ const resp = await getStravaUser(userStore.accessToken, stravaToken);
+ stravaStore.setUser(stravaToken, resp.athlete);
+ } catch {
+ stravaStore.logout();
+ }
+ }
+
+ // If setup is completed and the target page is 'Setup', redirect to 'Home' page
+ if (userStore.setupCompleted && to.name === 'Setup') {
+ return next({ name: 'Home' });
+ }
+
+ // If login is not needed and the target page is 'Login', redirect to 'Home' page
+ if (!loginNeeded && to.name === 'Login') {
+ return next({ name: 'Home' });
+ }
+
+ // If the user is authenticated and the target page is 'Login', redirect to 'Home' page
+ if (userStore.isAuthenticated() && to.name === 'Login') {
+ return next({ name: 'Home' });
+ }
+
next();
});
diff --git a/ui/src/services/activities.js b/ui/src/services/activities.js
index 5a27e0a..34f2a20 100644
--- a/ui/src/services/activities.js
+++ b/ui/src/services/activities.js
@@ -1,71 +1,39 @@
-import { getApiBaseURL } from './api';
-
-export async function fetchActivities(page) {
- const endpoint = `${getApiBaseURL()}/activities?page=${page}`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+import { makeRequest } from './api';
+
+export async function fetchActivities(accessToken, page) {
+ return await makeRequest({
+ endpoint: `/activities?page=${page}`,
+ accessToken,
+ error: 'Could not fetch activities',
+ json: true,
});
-
- if (!response.ok) {
- throw new Error('Could not fetch activities');
- }
-
- return await response.json();
}
-export async function getActivity(id) {
- const endpoint = `${getApiBaseURL()}/activities/${id}`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+export async function getActivity(accessToken, id) {
+ return await makeRequest({
+ endpoint: `/activities/${id}`,
+ accessToken,
+ error: 'Could not get activity',
+ json: true,
});
-
- if (!response.ok) {
- throw new Error('Could not get activity');
- }
-
- return await response.json();
}
-export async function getActivityGPX(id, accessToken) {
- const endpoint = `${getApiBaseURL()}/strava/activities/${id}/gpx`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- 'X-Strava-Authorization': accessToken,
- },
+export async function getActivityGPX(id, stravaToken, accessToken) {
+ return await makeRequest({
+ endpoint: `/strava/activities/${id}/gpx`,
+ stravaToken,
+ accessToken,
+ error: 'Could not get activity',
+ blob: true,
});
-
- if (!response.ok) {
- throw new Error('Could not get activity');
- }
-
- return await response.blob();
}
-export async function getActivityLaps(id, accessToken) {
- const endpoint = `${getApiBaseURL()}/strava/activities/${id}/laps`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- 'X-Strava-Authorization': accessToken,
- },
+export async function getActivityLaps(id, stravaToken, accessToken) {
+ return await makeRequest({
+ endpoint: `/strava/activities/${id}/laps`,
+ stravaToken,
+ accessToken,
+ error: 'Could not get activity laps',
+ json: true,
});
-
- if (!response.ok) {
- throw new Error('Could not get activity');
- }
-
- return await response.json();
}
diff --git a/ui/src/services/api.js b/ui/src/services/api.js
index cde6a72..163e7ab 100644
--- a/ui/src/services/api.js
+++ b/ui/src/services/api.js
@@ -12,4 +12,49 @@ function getApiBaseURL() {
return `${getDomain()}/api`;
}
-export { getDomain, getApiBaseURL };
+class APIError extends Error {
+ constructor(message, response) {
+ super(message);
+ this.response = response;
+ }
+}
+
+async function makeRequest(payload) {
+ const endpoint = `${getApiBaseURL()}${payload.endpoint}`;
+
+ const response = await fetch(endpoint, {
+ method: payload.method || 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ ...(payload.stravaToken
+ ? {
+ 'X-Strava-Authorization': payload.stravaToken,
+ }
+ : {}),
+ ...(payload.accessToken
+ ? {
+ Authorization: `Bearer ${payload.accessToken}`,
+ }
+ : {}),
+ },
+ ...(payload.body ? { body: JSON.stringify(payload.body) } : {}),
+ });
+
+ if (!response.ok) {
+ const errorMsg = payload.error || 'API Request Failed';
+ console.error(errorMsg, response);
+ throw new APIError(errorMsg, response);
+ }
+
+ if (payload.json) {
+ return await response.json();
+ }
+
+ if (payload.blob) {
+ return await response.blob();
+ }
+
+ return response;
+}
+
+export { getDomain, getApiBaseURL, makeRequest, APIError };
diff --git a/ui/src/services/athletes.js b/ui/src/services/athletes.js
index cd53e6f..86860af 100644
--- a/ui/src/services/athletes.js
+++ b/ui/src/services/athletes.js
@@ -1,35 +1,19 @@
-import { getApiBaseURL } from './api';
-
-export async function fetchAthletes(page) {
- const endpoint = `${getApiBaseURL()}/athletes?page=${page}`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+import { makeRequest } from './api';
+
+export async function fetchAthletes(accessToken, page) {
+ return await makeRequest({
+ endpoint: `/athletes?page=${page}`,
+ json: true,
+ error: 'Could not fetch athletes',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not fetch athletes');
- }
-
- return await response.json();
}
-export async function getAthlete(id) {
- const endpoint = `${getApiBaseURL()}/athletes/${id}`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+export async function getAthlete(accessToken, id) {
+ return await makeRequest({
+ endpoint: `/athletes/${id}`,
+ json: true,
+ error: 'Could not get athlete',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not get athlete');
- }
-
- return await response.json();
}
diff --git a/ui/src/services/auth.js b/ui/src/services/auth.js
index e24da86..45321da 100644
--- a/ui/src/services/auth.js
+++ b/ui/src/services/auth.js
@@ -1,37 +1,43 @@
-import { getDomain, getApiBaseURL } from './api';
-
-export async function getAuthorizationURL() {
- const callbackURL = `${getDomain()}/app/login`;
- const endpoint = `${getApiBaseURL()}/strava/authorization-url?callback_url=${callbackURL}`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+import { getDomain, makeRequest } from './api';
+
+export const loginTypeEnum = {
+ anonymous: 'anonymous',
+ protected: 'protected',
+};
+
+export const loginTypes = [
+ { name: 'Anonymous', code: loginTypeEnum.anonymous },
+ { name: 'Protected', code: loginTypeEnum.protected },
+];
+
+export async function getStravaAuthorizationURL(accessToken) {
+ const callbackURL = `${getDomain()}/app/strava-login`;
+
+ return await makeRequest({
+ endpoint: `/strava/authorization-url?callback_url=${callbackURL}`,
+ json: true,
+ error: 'Could not fetch user config',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not fetch user config');
- }
-
- return await response.json();
}
-export async function getAccessToken(code) {
- const endpoint = `${getApiBaseURL()}/strava/token`;
-
- const response = await fetch(endpoint, {
+export async function getStravaAccessToken(accessToken, code) {
+ return await makeRequest({
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ code }),
+ endpoint: `/strava/token`,
+ body: { code },
+ error: 'Could not fetch access token',
+ json: true,
+ accessToken,
});
+}
- if (!response.ok) {
- throw new Error('Could not fetch access token');
- }
-
- return await response.json();
+export async function login(data) {
+ return await makeRequest({
+ method: 'POST',
+ endpoint: '/auth/token',
+ body: data,
+ error: 'Could not login',
+ json: true,
+ });
}
diff --git a/ui/src/services/components.js b/ui/src/services/components.js
index ba0a5aa..dca3caf 100644
--- a/ui/src/services/components.js
+++ b/ui/src/services/components.js
@@ -1,4 +1,4 @@
-import { getApiBaseURL } from './api';
+import { makeRequest } from './api';
export const componentTypeEnum = {
table: 'table',
@@ -14,87 +14,52 @@ export const componentTypes = [
{ name: 'Line Chart', code: componentTypeEnum.lineChart },
];
-export async function fetchComponents(dashId) {
- const endpoint = `${getApiBaseURL()}/dashboards/${dashId}/components`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+export async function fetchComponents(accessToken, dashId) {
+ return await makeRequest({
+ endpoint: `/dashboards/${dashId}/components`,
+ json: true,
+ error: 'Could not fetch dashboard components',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not fetch dashboard components');
- }
-
- return await response.json();
}
-export async function createComponent(dashId, data) {
- const endpoint = `${getApiBaseURL()}/dashboards/${dashId}/components`;
-
- const response = await fetch(endpoint, {
+export async function createComponent(accessToken, dashId, data) {
+ return await makeRequest({
+ endpoint: `/dashboards/${dashId}/components`,
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(data),
+ body: data,
+ json: true,
+ error: 'Could not create a component',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not create a component');
- }
-
- return await response.json();
}
-export async function updateComponent(dashId, compId, data) {
- const endpoint = `${getApiBaseURL()}/dashboards/${dashId}/components/${compId}`;
-
- const response = await fetch(endpoint, {
+export async function updateComponent(accessToken, dashId, compId, data) {
+ return await makeRequest({
+ endpoint: `/dashboards/${dashId}/components/${compId}`,
method: 'PUT',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(data),
+ body: data,
+ json: true,
+ error: 'Could not create a component',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not create a component');
- }
-
- return await response.json();
}
-export async function deleteComponent(dashId, compId) {
- const endpoint = `${getApiBaseURL()}/dashboards/${dashId}/components/${compId}`;
-
- const response = await fetch(endpoint, {
+export async function deleteComponent(accessToken, dashId, compId) {
+ return await makeRequest({
+ endpoint: `/dashboards/${dashId}/components/${compId}`,
method: 'DELETE',
- headers: {
- 'Content-Type': 'application/json',
- },
+ error: 'Could not delete a component',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not delete a component');
- }
}
-export async function runComponent(dashId, compId) {
- const endpoint = `${getApiBaseURL()}/dashboards/${dashId}/components/${compId}/run`;
-
- const response = await fetch(endpoint, {
+export async function runComponent(accessToken, dashId, compId) {
+ return await makeRequest({
+ endpoint: `/dashboards/${dashId}/components/${compId}/run`,
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
+ json: true,
+ error: 'Could not run component',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not run component');
- }
-
- return await response.json();
}
diff --git a/ui/src/services/config.js b/ui/src/services/config.js
new file mode 100644
index 0000000..eabca08
--- /dev/null
+++ b/ui/src/services/config.js
@@ -0,0 +1,39 @@
+import { makeRequest } from './api';
+
+export async function getUserConfig(accessToken) {
+ return await makeRequest({
+ endpoint: '/config',
+ accessToken,
+ error: 'Could not fetch user config',
+ json: true,
+ });
+}
+
+export async function checkSetupCompleted() {
+ return await makeRequest({
+ endpoint: '/config/setup',
+ json: true,
+ error: 'Could not fetch setup status',
+ });
+}
+
+export async function completeSetup(config) {
+ return await makeRequest({
+ method: 'POST',
+ endpoint: '/config/setup',
+ body: config,
+ error: 'Could not save setup',
+ json: true,
+ });
+}
+
+export async function saveUserConfig(accessToken, config) {
+ return await makeRequest({
+ method: 'PUT',
+ endpoint: '/config',
+ body: config,
+ accessToken,
+ json: true,
+ error: 'Could not save user config',
+ });
+}
diff --git a/ui/src/services/dashboars.js b/ui/src/services/dashboars.js
index d36d6d1..74cd4e4 100644
--- a/ui/src/services/dashboars.js
+++ b/ui/src/services/dashboars.js
@@ -1,103 +1,60 @@
-import { getApiBaseURL } from './api';
-
-export async function fetchDashboards() {
- const endpoint = `${getApiBaseURL()}/dashboards`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+import { makeRequest } from './api';
+
+export async function fetchDashboards(accessToken) {
+ return await makeRequest({
+ endpoint: '/dashboards',
+ json: true,
+ error: 'Could not fetch dashboards',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not fetch dashboards');
- }
-
- return await response.json();
}
-export async function getDashboard(id) {
- const endpoint = `${getApiBaseURL()}/dashboards/${id}`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+export async function getDashboard(accessToken, id) {
+ return await makeRequest({
+ endpoint: `/dashboards/${id}`,
+ json: true,
+ error: 'Could not get dashboard',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not get dashboard');
- }
-
- return await response.json();
}
-export async function createDashboard(data) {
- const endpoint = `${getApiBaseURL()}/dashboards`;
-
- const response = await fetch(endpoint, {
+export async function createDashboard(accessToken, data) {
+ return await makeRequest({
+ endpoint: '/dashboards',
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(data),
+ body: data,
+ json: true,
+ error: 'Could not create a dashboard',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not create a dashboard');
- }
-
- return await response.json();
}
-export async function updateDashboard(id, data) {
- const endpoint = `${getApiBaseURL()}/dashboards/${id}`;
-
- const response = await fetch(endpoint, {
+export async function updateDashboard(accessToken, id, data) {
+ return await makeRequest({
+ endpoint: `/dashboards/${id}`,
method: 'PUT',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(data),
+ body: data,
+ json: true,
+ error: 'Could not update a dashboard',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not update a dashboard');
- }
-
- return await response.json();
}
-export async function deleteDashboard(id) {
- const endpoint = `${getApiBaseURL()}/dashboards/${id}`;
-
- const response = await fetch(endpoint, {
+export async function deleteDashboard(accessToken, id) {
+ return await makeRequest({
+ endpoint: `/dashboards/${id}`,
method: 'DELETE',
- headers: {
- 'Content-Type': 'application/json',
- },
+ error: 'Could not delete a dashboard',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not delete a dashboard');
- }
}
-export async function runDashboard(id) {
- const endpoint = `${getApiBaseURL()}/dashboards/${id}/run`;
-
- const response = await fetch(endpoint, {
+export async function runDashboard(accessToken, id) {
+ return await makeRequest({
+ endpoint: `/dashboards/${id}/run`,
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
+ json: true,
+ error: 'Could not run dashboard',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not run dashboard');
- }
-
- return await response.json();
}
diff --git a/ui/src/services/gears.js b/ui/src/services/gears.js
index 190fbbc..90c63b8 100644
--- a/ui/src/services/gears.js
+++ b/ui/src/services/gears.js
@@ -1,35 +1,19 @@
-import { getApiBaseURL } from './api';
-
-export async function fetchGears(page) {
- const endpoint = `${getApiBaseURL()}/gears?page=${page}`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+import { makeRequest } from './api';
+
+export async function fetchGears(accessToken, page) {
+ return await makeRequest({
+ endpoint: `/gears?page=${page}`,
+ json: true,
+ error: 'Could not fetch gears',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not fetch gears');
- }
-
- return await response.json();
}
-export async function getGear(id) {
- const endpoint = `${getApiBaseURL()}/gears/${id}`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+export async function getGear(accessToken, id) {
+ return await makeRequest({
+ endpoint: `/gears/${id}`,
+ json: true,
+ error: 'Could not get gear',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not get gear');
- }
-
- return await response.json();
}
diff --git a/ui/src/services/user.js b/ui/src/services/user.js
index b4537ab..067cf58 100644
--- a/ui/src/services/user.js
+++ b/ui/src/services/user.js
@@ -1,4 +1,4 @@
-import { getApiBaseURL } from './api';
+import { makeRequest } from './api';
export const taskStatusEnum = {
pending: 'pending',
@@ -7,113 +7,48 @@ export const taskStatusEnum = {
archived: 'archived',
};
-export async function getUserConfig() {
- const endpoint = `${getApiBaseURL()}/config`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+export async function getStravaUser(accessToken, stravaToken) {
+ return await makeRequest({
+ endpoint: '/strava/me',
+ json: true,
+ error: 'Could not fetch user',
+ stravaToken,
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not fetch user config');
- }
-
- return await response.json();
}
-export async function getUserMe(accessToken) {
- const endpoint = `${getApiBaseURL()}/strava/me`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- 'X-Strava-Authorization': accessToken,
- },
+export async function getTaskDetail(accessToken, id) {
+ return await makeRequest({
+ endpoint: `/user/task/${id}`,
+ json: true,
+ error: 'Could not fetch task detail',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not fetch user');
- }
-
- return await response.json();
-}
-
-export async function getTaskDetail(id) {
- const endpoint = `${getApiBaseURL()}/user/task/${id}`;
-
- const response = await fetch(endpoint, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
- });
-
- if (!response.ok) {
- throw new Error('Could not fetch task detail');
- }
-
- return await response.json();
}
-export async function triggerSync(accessToken) {
- const endpoint = `${getApiBaseURL()}/strava/sync`;
-
- const response = await fetch(endpoint, {
+export async function triggerSync(accessToken, stravaToken) {
+ return await makeRequest({
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-Strava-Authorization': accessToken,
- },
+ endpoint: '/strava/sync',
+ json: true,
+ error: 'Could not trigger a sync task',
+ accessToken,
+ stravaToken,
});
-
- if (!response.ok) {
- throw new Error('Could not fetch task detail');
- }
-
- return await response.json();
}
-export async function saveUserConfig(config) {
- const endpoint = `${getApiBaseURL()}/config`;
-
- const response = await fetch(endpoint, {
- method: 'PUT',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(config),
- });
-
- if (!response.ok) {
- throw new Error('Could not save user config');
- }
-
- return await response.json();
-}
-
-export async function runQuery(query) {
- const endpoint = `${getApiBaseURL()}/user/query`;
-
- const response = await fetch(endpoint, {
+export async function runQuery(accessToken, query) {
+ return await makeRequest({
+ endpoint: '/user/query',
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(query),
+ body: query,
+ json: true,
+ error: 'Could not run query',
+ accessToken,
});
-
- if (!response.ok) {
- throw new Error('Could not run query');
- }
-
- return await response.json();
}
-export async function waitAsyncTask(task) {
+export async function waitAsyncTask(accessToken, task) {
const delay = async (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
@@ -121,7 +56,7 @@ export async function waitAsyncTask(task) {
let taskStatus = task.status;
while (![taskStatusEnum.success, taskStatusEnum.error].includes(taskStatus)) {
await delay(1000);
- task = await getTaskDetail(task.id);
+ task = await getTaskDetail(accessToken, task.id);
taskStatus = task.status;
}
diff --git a/ui/src/store/strava.js b/ui/src/store/strava.js
new file mode 100644
index 0000000..d31104c
--- /dev/null
+++ b/ui/src/store/strava.js
@@ -0,0 +1,32 @@
+import { defineStore } from 'pinia';
+import Cookies from 'js-cookie';
+
+const cookieKey = 'strava_accessToken';
+
+export const useStravaStore = defineStore('strava', {
+ state: () => ({
+ accessToken: '',
+ user: {},
+ }),
+ actions: {
+ logout() {
+ this.user = {};
+ this.accessToken = '';
+ Cookies.remove(cookieKey);
+ },
+ login(accessToken, user) {
+ this.setUser(accessToken, user);
+ Cookies.set(cookieKey, accessToken);
+ },
+ setUser(accessToken, user) {
+ this.accessToken = accessToken;
+ this.user = user;
+ },
+ getAccessToken() {
+ return Cookies.get(cookieKey);
+ },
+ isAuthenticated() {
+ return this.accessToken !== '';
+ },
+ },
+});
diff --git a/ui/src/store/user.js b/ui/src/store/user.js
index b6e5c1b..e791ea0 100644
--- a/ui/src/store/user.js
+++ b/ui/src/store/user.js
@@ -1,24 +1,42 @@
import { defineStore } from 'pinia';
import Cookies from 'js-cookie';
+import { loginTypeEnum } from '@/services/auth';
+
+const cookieKey = 'app_accessToken';
export const useUserStore = defineStore('user', {
state: () => ({
accessToken: '',
- user: {},
+ config: {},
+ setupCompleted: false,
+ loginType: '',
}),
actions: {
logout() {
- this.user = {};
this.accessToken = '';
- Cookies.remove('accessToken');
- },
- login(accessToken, user) {
- this.setUser(accessToken, user);
- Cookies.set('accessToken', accessToken);
+ this.config = {};
+ Cookies.remove(cookieKey);
},
- setUser(accessToken, user) {
+ login(config, accessToken) {
this.accessToken = accessToken;
- this.user = user;
+ this.config = config;
+ Cookies.set(cookieKey, accessToken);
+ },
+ getAccessToken() {
+ return Cookies.get(cookieKey);
+ },
+ setSetupCompleted(loginType, status) {
+ this.setupCompleted = status;
+ this.loginType = loginType;
+ },
+ setConfig(config) {
+ this.config = config;
+ },
+ isAuthenticated() {
+ return this.accessToken !== '';
+ },
+ loginNeeded() {
+ return this.loginType === loginTypeEnum.protected;
},
},
});