Skip to content

Commit c4c0f84

Browse files
authored
File Structure Improvements (#70)
* move docs to assets * Update API package and imports * move api to aliased 'package' * move loadAlbums to assets * remove unused SplitPane * import from aliased components image * import from modals dir * Rename auth form * import from components * add auth work around for development * add path to navs in header
1 parent 6537f97 commit c4c0f84

32 files changed

Lines changed: 359 additions & 310 deletions

.env.development

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
VITE_LOCAL=true

src/api/gh/api.ts

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
1-
import { Endpoints } from "@octokit/types";
21
import { Octokit } from "octokit";
32

4-
const octokit = new Octokit();
3+
import { getRepoReadMe, listUserReposResponseData } from "./types";
54

6-
export type listUserReposResponseData =
7-
Endpoints["GET /repos/{owner}/{repo}"]["response"]["data"];
5+
const octokit = new Octokit();
86

9-
export async function fetchProjects(
10-
num_projects = 30
11-
): Promise<listUserReposResponseData[]> {
12-
const response = await octokit.request(
13-
`GET /users/RexGreenway/repos?sort=pushed&per_page=${num_projects}`
14-
);
15-
return await response.data;
16-
}
7+
const ghApi = {
8+
fetchProjects: async (
9+
num_projects = 30,
10+
): Promise<listUserReposResponseData[]> => {
11+
const response = await octokit.request(
12+
`GET /users/RexGreenway/repos?sort=pushed&per_page=${num_projects}`,
13+
);
14+
return await response.data;
15+
},
1716

18-
export type getRepoReadMe =
19-
Endpoints["GET /repos/{owner}/{repo}/contents/{path}"]["response"]["data"];
17+
fetchReadMe: async (repo: string): Promise<getRepoReadMe> => {
18+
const response = await octokit.request(
19+
`GET /repos/RexGreenway/${repo}/contents/README.md`,
20+
);
21+
return await response.data;
22+
},
23+
};
2024

21-
export async function fetchReadMe(repo: string): Promise<getRepoReadMe> {
22-
const response = await octokit.request(
23-
`GET /repos/RexGreenway/${repo}/contents/README.md`
24-
);
25-
return await response.data;
26-
}
25+
export default ghApi;

src/api/gh/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import ghApi from "./api";
2+
3+
export default ghApi;

src/api/gh/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { Endpoints } from "@octokit/types";
2+
3+
export type listUserReposResponseData =
4+
Endpoints["GET /repos/{owner}/{repo}"]["response"]["data"];
5+
6+
export type getRepoReadMe =
7+
Endpoints["GET /repos/{owner}/{repo}/contents/{path}"]["response"]["data"];

src/api/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import ghApi from "./gh";
2+
import rexApi from "./rex-api";
3+
4+
export { rexApi, ghApi };

src/api/rex-api/api.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { type Image, Size, type TokenResponse } from "./model";
2+
3+
// CONSTANTS
4+
// export const API_URL = "http://127.0.0.1:8080";
5+
export const API_URL = "https://rex-api-505972842640.europe-west2.run.app";
6+
7+
export const THUMBNAIL_BUCKET = "rex-thumbnails";
8+
9+
/**
10+
* Rex API client for authentication, photography, and utility operations.
11+
* Provides methods to interact with the Rex API including token management,
12+
* photo fetching, and downloading.
13+
*/
14+
const rexApi = {
15+
// UTILITY FUNCS
16+
getThumbnailURL: (image_name: string): string => {
17+
return `https://storage.googleapis.com/${THUMBNAIL_BUCKET}/${image_name}`;
18+
},
19+
20+
// REQUESTS
21+
22+
/**
23+
* Wake's up the API.
24+
*/
25+
wakeUp: async (): Promise<void> => {
26+
const response = await fetch(`${API_URL}/`);
27+
if (!response.ok) {
28+
console.error(`Rex API did not wake up... ${response.status}`);
29+
}
30+
},
31+
32+
// - AUTH
33+
34+
/**
35+
* Authenticates and fetches Bearer Token.
36+
*
37+
* @param {FormData} authForm
38+
*
39+
* @returns {TokenResponse} Token Response.
40+
*/
41+
getToken: async (authForm: FormData): Promise<TokenResponse> => {
42+
const response = await fetch(`${API_URL}/token`, {
43+
method: "POST",
44+
body: authForm,
45+
});
46+
47+
if (!response.ok) {
48+
throw new Error(`Fetching Token failed | status: ${response.status}`);
49+
}
50+
51+
return await response.json();
52+
},
53+
54+
// - PHOTOGRAPHY
55+
56+
/**
57+
* Fetches a photo from a given album.
58+
*
59+
* @param {string} image_name
60+
* @param {Size} [size=Size.LARGE] Optional
61+
*
62+
* @returns {Image} The desired photo.
63+
*/
64+
getPhoto: async (
65+
token: string,
66+
image_name: string,
67+
size: Size = Size.MEDIUM,
68+
): Promise<Image> => {
69+
const encoded_path = encodeURI(`${image_name}?size=${size}`);
70+
const url = `${API_URL}/photography/${encoded_path}`;
71+
72+
const response = await fetch(url, {
73+
headers: { Authorization: `Bearer ${token}` },
74+
});
75+
76+
if (response.status == 401) {
77+
throw new Error(`Fetching Photo failed | unauthenticated`);
78+
} else if (!response.ok) {
79+
throw new Error(
80+
`failed to fetch photo '${image_name}' | status: ${response.status}`,
81+
);
82+
}
83+
84+
return await response.json();
85+
},
86+
87+
/**
88+
* Downloads a photo.
89+
*
90+
* @param {string} image_name
91+
* @param {Size} [size=Size.MEDIUM] Optional
92+
*
93+
* @returns {Image} The desired photo.
94+
*/
95+
downloadPhoto: async (
96+
token: string,
97+
image_name: string,
98+
size: Size = Size.MEDIUM,
99+
): Promise<void> => {
100+
const encoded_path = encodeURI(`${image_name}/download?size=${size}`);
101+
const url = `${API_URL}/photography/${encoded_path}`;
102+
103+
const response = await fetch(url, {
104+
headers: { Authorization: `Bearer ${token}` },
105+
});
106+
107+
if (response.status == 401) {
108+
throw new Error(`Fetching Photo failed | unauthenticated`);
109+
} else if (!response.ok) {
110+
throw new Error(
111+
`failed to download photo '${image_name}' | status: ${response.status}`,
112+
);
113+
}
114+
115+
const blob = await response.blob();
116+
const blobUrl = URL.createObjectURL(blob);
117+
const link = document.createElement("a");
118+
link.href = blobUrl;
119+
link.download = image_name;
120+
document.body.appendChild(link);
121+
link.click();
122+
document.body.removeChild(link);
123+
URL.revokeObjectURL(blobUrl);
124+
},
125+
};
126+
127+
export default rexApi;

src/api/rex-api/fetchPhotography.ts

Lines changed: 0 additions & 112 deletions
This file was deleted.

src/api/rex-api/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import rexApi from "./api";
2+
3+
export default rexApi;

src/api/rex-api/model.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,3 @@
1-
// CONSTANTS
2-
// export const API_URL = "http://127.0.0.1:8080";
3-
export const API_URL = "https://rex-api-505972842640.europe-west2.run.app";
4-
5-
export const THUMBNAIL_BUCKET = "rex-thumbnails";
6-
7-
interface PhotoInfo {
8-
alt?: string; // alt text for the photo
9-
}
10-
11-
export interface Album {
12-
name: string;
13-
thumbnail: string;
14-
film_stock: string;
15-
photos: { [name: string]: PhotoInfo };
16-
}
17-
181
// RESPONSE TYPES
192

203
export interface TokenResponse {
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
import { Album } from "./model";
1+
interface PhotoInfo {
2+
alt?: string; // alt text for the photo
3+
}
4+
5+
interface Album {
6+
name: string;
7+
thumbnail: string;
8+
film_stock: string;
9+
photos: { [name: string]: PhotoInfo };
10+
}
211

312
// Find all the film roll JSON files
4-
const rolls = import.meta.glob<{ default: Record<string, Album> }>(
5-
"../../assets/albums/*.json",
6-
{ eager: true }
7-
);
13+
const rolls = import.meta.glob<{ default: Record<string, Album> }>("./*.json", {
14+
eager: true,
15+
});
816

917
const loadAlbums = (): Record<string, Album> => {
1018
const merged: Record<string, Album> = {};
@@ -16,4 +24,6 @@ const loadAlbums = (): Record<string, Album> => {
1624
return merged;
1725
};
1826

19-
export const ALBUMS: { [key: string]: Album } = loadAlbums();
27+
const ALBUMS: { [key: string]: Album } = loadAlbums();
28+
29+
export default ALBUMS;

0 commit comments

Comments
 (0)