Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
61 changes: 31 additions & 30 deletions front-end/lib/api.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {state} from "../index.mjs";
import {handleErrorDialog} from "../components/error.mjs";
import { state } from "../index.mjs";
import { handleErrorDialog } from "../components/error.mjs";

// === ABOUT THE STATE
// state gives you these two functions only
Expand All @@ -20,13 +20,13 @@ async function _apiRequest(endpoint, options = {}) {
const defaultOptions = {
headers: {
"Content-Type": "application/json",
...(token ? {Authorization: `Bearer ${token}`} : {}),
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
mode: "cors",
credentials: "include",
};

const fetchOptions = {...defaultOptions, ...options};
const fetchOptions = { ...defaultOptions, ...options };
const url = endpoint.startsWith("http") ? endpoint : `${baseUrl}${endpoint}`;

try {
Expand Down Expand Up @@ -54,7 +54,7 @@ async function _apiRequest(endpoint, options = {}) {
const contentType = response.headers.get("content-type");
return contentType?.includes("application/json")
? await response.json()
: {success: true};
: { success: true };
} catch (error) {
if (!error.status) {
// Only handle network errors here, response errors are handled above
Expand All @@ -70,19 +70,19 @@ function _updateProfile(username, profileData) {
const index = profiles.findIndex((p) => p.username === username);

if (index !== -1) {
profiles[index] = {...profiles[index], ...profileData};
profiles[index] = { ...profiles[index], ...profileData };
} else {
profiles.push({username, ...profileData});
profiles.push({ username, ...profileData });
}
state.updateState({profiles});
state.updateState({ profiles });
}

// ====== AUTH methods
async function login(username, password) {
try {
const data = await _apiRequest("/login", {
method: "POST",
body: JSON.stringify({username, password}),
body: JSON.stringify({ username, password }),
});

if (data.success && data.token) {
Expand All @@ -96,20 +96,20 @@ async function login(username, password) {

return data;
} catch (error) {
return {success: false};
return { success: false };
}
}

async function getWhoToFollow() {
try {
const usernamesToFollow = await _apiRequest("/suggested-follows/3");

state.updateState({whoToFollow: usernamesToFollow});
state.updateState({ whoToFollow: usernamesToFollow });

return usernamesToFollow;
} catch (error) {
// Error already handled by _apiRequest
state.updateState({usernamesToFollow: []});
state.updateState({ usernamesToFollow: [] });
return [];
}
}
Expand All @@ -118,7 +118,7 @@ async function signup(username, password) {
try {
const data = await _apiRequest("/register", {
method: "POST",
body: JSON.stringify({username, password}),
body: JSON.stringify({ username, password }),
});

if (data.success && data.token) {
Expand All @@ -132,20 +132,21 @@ async function signup(username, password) {

return data;
} catch (error) {
return {success: false};
return { success: false };
}
}

function logout() {
state.destroyState();
return {success: true};
window.location.hash = "/";
return { success: true };
}

// ===== BLOOM methods
async function getBloom(bloomId) {
const endpoint = `/bloom/${bloomId}`;
const bloom = await _apiRequest(endpoint);
state.updateState({singleBloomToShow: bloom});
state.updateState({ singleBloomToShow: bloom });
return bloom;
}

Expand All @@ -156,18 +157,18 @@ async function getBlooms(username) {
const blooms = await _apiRequest(endpoint);

if (username) {
_updateProfile(username, {blooms});
_updateProfile(username, { blooms });
} else {
state.updateState({timelineBlooms: blooms});
state.updateState({ timelineBlooms: blooms });
}

return blooms;
} catch (error) {
// Error already handled by _apiRequest
if (username) {
_updateProfile(username, {blooms: []});
_updateProfile(username, { blooms: [] });
} else {
state.updateState({timelineBlooms: []});
state.updateState({ timelineBlooms: [] });
}
return [];
}
Expand All @@ -189,15 +190,15 @@ async function getBloomsByHashtag(hashtag) {
return blooms;
} catch (error) {
// Error already handled by _apiRequest
return {success: false};
return { success: false };
}
}

async function postBloom(content) {
try {
const data = await _apiRequest("/bloom", {
method: "POST",
body: JSON.stringify({content}),
body: JSON.stringify({ content }),
});

if (data.success) {
Expand All @@ -208,7 +209,7 @@ async function postBloom(content) {
return data;
} catch (error) {
// Error already handled by _apiRequest
return {success: false};
return { success: false };
}
}

Expand All @@ -225,24 +226,24 @@ async function getProfile(username) {
const currentUsername = profileData.username;
const fullProfileData = await _apiRequest(`/profile/${currentUsername}`);
_updateProfile(currentUsername, fullProfileData);
state.updateState({currentUser: currentUsername, isLoggedIn: true});
state.updateState({ currentUser: currentUsername, isLoggedIn: true });
}

return profileData;
} catch (error) {
// Error already handled by _apiRequest
if (!username) {
state.updateState({isLoggedIn: false, currentUser: null});
state.updateState({ isLoggedIn: false, currentUser: null });
}
return {success: false};
return { success: false };
}
}

async function followUser(username) {
try {
const data = await _apiRequest("/follow", {
method: "POST",
body: JSON.stringify({follow_username: username}),
body: JSON.stringify({ follow_username: username }),
});

if (data.success) {
Expand All @@ -255,7 +256,7 @@ async function followUser(username) {

return data;
} catch (error) {
return {success: false};
return { success: false };
}
}

Expand All @@ -277,7 +278,7 @@ async function unfollowUser(username) {
return data;
} catch (error) {
// Error already handled by _apiRequest
return {success: false};
return { success: false };
}
}

Expand All @@ -300,4 +301,4 @@ const apiService = {
getWhoToFollow,
};

export {apiService};
export { apiService };
31 changes: 17 additions & 14 deletions front-end/views/hashtag.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,24 @@ function hashtagView(hashtag) {
createLogin
);
document
.querySelector("[data-action='login']")
?.addEventListener("click", handleLogin);
.querySelector("[data-form='login']")
?.addEventListener("submit", handleLogin);

renderOne(
state.currentHashtag,
getHeadingContainer(),
"heading-template",
createHeading
);
renderEach(
state.hashtagBlooms || [],
getTimelineContainer(),
"bloom-template",
createBloom
);
// Only show hashtag content if logged in
if (state.isLoggedIn) {
renderOne(
state.currentHashtag,
getHeadingContainer(),
"heading-template",
createHeading
);
renderEach(
state.hashtagBlooms || [],
getTimelineContainer(),
"bloom-template",
createBloom
);
}
}

export {hashtagView};
47 changes: 25 additions & 22 deletions front-end/views/profile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "../index.mjs";
import {createLogin, handleLogin} from "../components/login.mjs";
import {createLogout, handleLogout} from "../components/logout.mjs";
import {createProfile, handleFollow} from "../components/profile.mjs";
import {createProfile} from "../components/profile.mjs";
import {createBloom} from "../components/bloom.mjs";

// Profile view - just this person's blooms and their profile
Expand All @@ -19,7 +19,7 @@ function profileView(username) {
const existingProfile = state.profiles.find((p) => p.username === username);

// Only fetch profile if we don't have it or if it's incomplete
if (!existingProfile || !existingProfile.recent_blooms) {
if (!existingProfile?.recent_blooms) {
apiService.getProfile(username);
}

Expand All @@ -39,27 +39,30 @@ function profileView(username) {
createLogin
);
document
.querySelector("[data-action='login']")
?.addEventListener("click", handleLogin);
.querySelector("[data-form='login']")
?.addEventListener("submit", handleLogin);

const profileData = state.profiles.find((p) => p.username === username);
if (profileData) {
renderOne(
{
profileData,
whoToFollow: state.isLoggedIn ? state.whoToFollow : [],
isLoggedIn: state.isLoggedIn,
},
getProfileContainer(),
"profile-template",
createProfile
);
renderEach(
profileData.recent_blooms || [],
getTimelineContainer(),
"bloom-template",
createBloom
);
// Only show profile content if logged in
if (state.isLoggedIn) {
const profileData = state.profiles.find((p) => p.username === username);
if (profileData) {
renderOne(
{
profileData,
whoToFollow: state.whoToFollow,
isLoggedIn: state.isLoggedIn,
},
getProfileContainer(),
"profile-template",
createProfile
);
renderEach(
profileData.recent_blooms || [],
getTimelineContainer(),
"bloom-template",
createBloom
);
}
}
}

Expand Down