Skip to content

Commit

Permalink
feat: strip out the all for now
Browse files Browse the repository at this point in the history
  • Loading branch information
joekiller committed Jul 5, 2024
1 parent 678e964 commit bd700c5
Show file tree
Hide file tree
Showing 13 changed files with 5,189 additions and 228 deletions.
5,026 changes: 4,954 additions & 72 deletions example-web/react2/package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion example-web/react2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"author": "",
"license": "ISC",
"dependencies": {
"date-fns": "^3.6.0",
"idb-keyval": "^6.2.1",
"ps99-api": "file:../..",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand All @@ -19,12 +21,15 @@
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
"html-webpack-plugin": "^5.6.0",
"ts-loader": "^9.5.1",
"typescript": "^5.5.2",
"webpack": "^5.92.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
"webpack-dev-server": "^5.0.4",
"workbox-webpack-plugin": "^7.1.0"
}
}
1 change: 1 addition & 0 deletions example-web/react2/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"description": "Pet Simulator 99 PWA",
"icons": [
{
"src": "/icons/icon-192x192.png",
Expand Down
12 changes: 4 additions & 8 deletions example-web/react2/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Header from "./components/Header";
import CollectionsIndex from "./components/CollectionsIndex";
import CollectionConfigIndex from "./components/CollectionConfigIndex";
import DynamicCollectionConfigData from "./components/DynamicCollectionConfigData";
import Footer from "./components/Footer";

const App: React.FC = () => {
return (
Expand All @@ -13,15 +14,10 @@ const App: React.FC = () => {
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/collections" element={<CollectionsIndex />} />
<Route
path="/collections/:collectionName"
element={<CollectionConfigIndex />}
/>
<Route
path="/collections/:collectionName/:configName"
element={<DynamicCollectionConfigData />}
/>
<Route path="/collections/:collectionName" element={<CollectionConfigIndex />} />
<Route path="/collections/:collectionName/:configName" element={<DynamicCollectionConfigData />} />
</Routes>
<Footer />
</Router>
);
};
Expand Down
3 changes: 0 additions & 3 deletions example-web/react2/src/components/CollectionConfigIndex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ const CollectionConfigIndex: React.FC = () => {
<div>
<h2>{collectionName} Configurations</h2>
<ul>
<li>
<Link to={`/collections/${collectionName}/all`}>All</Link>
</li>
{configNames.map((configName, index) => (
<li key={index}>
<Link
Expand Down
119 changes: 6 additions & 113 deletions example-web/react2/src/components/DynamicCollectionConfigData.tsx
Original file line number Diff line number Diff line change
@@ -1,128 +1,21 @@
import React, {
lazy,
Suspense,
useEffect,
useState,
useRef,
useCallback,
} from "react";
import React, { lazy, Suspense } from "react";
import { useParams } from "react-router-dom";
import {
PetSimulator99API,
CollectionName,
Collection,
CollectionConfigData,
} from "ps99-api";
import { CollectionName } from "ps99-api";

const DynamicCollectionConfigData: React.FC = () => {
const { collectionName, configName } = useParams<{
collectionName: CollectionName;
configName: string;
}>();
const { collectionName, configName } = useParams<{ collectionName: CollectionName; configName: string }>();

if (!collectionName) {
return <div>Invalid collection name</div>;
}

if (configName === "all") {
return <RenderAllConfigs collectionName={collectionName} />;
if (!collectionName || !configName) {
return <div>Invalid collection or config name</div>;
}

const Component = lazy(() => import(`./${collectionName}Component`));

return (
<Suspense fallback={<div>Loading...</div>}>
<Component />
<Component configName={configName} />
</Suspense>
);
};

const RenderAllConfigs: React.FC<{ collectionName: CollectionName }> = ({
collectionName,
}) => {
const [configDataList, setConfigDataList] = useState<
Array<Collection<CollectionName>>
>([]);
const [page, setPage] = useState(0);
const [error, setError] = useState<string | null>(null);
const observer = useRef<IntersectionObserver | null>(null);
const loadMoreRef = useRef<HTMLDivElement | null>(null);

const fetchData = async (page: number) => {
try {
const api = new PetSimulator99API();
const response = await api.getCollection(collectionName);
if (response.status === "ok") {
const start = page * 20;
const end = start + 20;
setConfigDataList((prev) => [
...prev,
...response.data.slice(start, end),
]);
} else {
setError(response.error.message);
}
} catch (error) {
setError("Error fetching data");
console.error("Error fetching data:", error);
}
};

useEffect(() => {
fetchData(page);
}, [page]);

const lastElementRef = useCallback((node: HTMLDivElement | null) => {
if (observer.current) observer.current.disconnect();
observer.current = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
setPage((prevPage) => prevPage + 1);
}
});
if (node) observer.current.observe(node);
}, []);

if (error) {
return <div>Error: {error}</div>;
}

return (
<div>
{configDataList.map((configData, index) => {
const Component = lazy(() => import(`./${collectionName}Component`));
if (index === configDataList.length - 1) {
return (
<div ref={lastElementRef} key={index}>
<Suspense fallback={<div>Loading...</div>}>
<Component
configData={
configData.configData as CollectionConfigData<
typeof collectionName
>
}
/>
</Suspense>
</div>
);
} else {
return (
<div key={index}>
<Suspense fallback={<div>Loading...</div>}>
<Component
configData={
configData.configData as CollectionConfigData<
typeof collectionName
>
}
/>
</Suspense>
</div>
);
}
})}
<div ref={loadMoreRef}></div>
</div>
);
};

export default DynamicCollectionConfigData;
60 changes: 60 additions & 0 deletions example-web/react2/src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { useState, useEffect } from "react";
import { useOnlineStatus } from "../hooks/useOnlineStatus";

const Footer: React.FC = () => {
const isOnline = useOnlineStatus();
const [lastUpdate, setLastUpdate] = useState<string | null>(null);
const [loading, setLoading] = useState(false);

const updateLastUpdate = () => {
setLastUpdate(new Date().toLocaleString());
};

useEffect(() => {
const fetchData = async () => {
setLoading(true);
// Simulate a fetch call to update lastUpdate time
await new Promise((resolve) => setTimeout(resolve, 1000));
updateLastUpdate();
setLoading(false);
};

fetchData();

window.addEventListener("online", updateLastUpdate);
window.addEventListener("offline", updateLastUpdate);

return () => {
window.removeEventListener("online", updateLastUpdate);
window.removeEventListener("offline", updateLastUpdate);
};
}, []);

return (
<footer
style={{
display: "flex",
justifyContent: "space-between",
padding: "1em",
borderTop: "1px solid #ccc",
}}
>
<div>
{loading ? (
<span>♻️ Loading...</span>
) : (
<span>Last update: {lastUpdate}</span>
)}
</div>
<div>
{isOnline ? (
<span style={{ color: "green" }}>● Online</span>
) : (
<span style={{ color: "red" }}>● Offline</span>
)}
</div>
</footer>
);
};

export default Footer;
15 changes: 6 additions & 9 deletions example-web/react2/src/components/GenericFetchComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ interface GenericFetchComponentProps<T> {
}

export const GenericFetchComponent = <T,>({
collectionName,
render,
configData,
}: GenericFetchComponentProps<T>) => {
collectionName,
render,
configData,
}: GenericFetchComponentProps<T>) => {
const { configName } = useParams<{ configName: string }>();
const [data, setData] = useState<T | null>(configData || null);
const [error, setError] = useState<string | null>(null);
Expand All @@ -23,12 +23,9 @@ export const GenericFetchComponent = <T,>({
const fetchData = async () => {
if (!configName) return;
const api = new PetSimulator99API();
const response: ApiResponseBody<any[]> =
await api.getCollection(collectionName);
const response: ApiResponseBody<any[]> = await api.getCollection(collectionName);
if (response.status === "ok") {
const item = response.data.find(
(item) => item.configName === configName,
);
const item = response.data.find((item) => item.configName === configName);
if (item) {
setData(item.configData);
} else {
Expand Down
36 changes: 15 additions & 21 deletions example-web/react2/src/components/ImageComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,55 @@ interface ImageProps {
}

const MAX_CONCURRENT_REQUESTS = 5;
let currentRequests = 0;
const queue: (() => void)[] = [];
const requestQueue: Array<() => void> = [];
let activeRequests = 0;

const processQueue = () => {
if (queue.length > 0 && currentRequests < MAX_CONCURRENT_REQUESTS) {
const nextRequest = queue.shift();
if (activeRequests < MAX_CONCURRENT_REQUESTS && requestQueue.length > 0) {
const nextRequest = requestQueue.shift();
if (nextRequest) {
currentRequests++;
activeRequests++;
nextRequest();
}
}
};

const ImageComponent: React.FC<ImageProps> = ({ src, alt }) => {
const [imageUrl, setImageUrl] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
const fetchImage = async () => {
const api = new PetSimulator99API();
try {
const api = new PetSimulator99API();
const imageBlob = await api.getImage(src);
const imageUrl = URL.createObjectURL(
new Blob([imageBlob], { type: "image/png" }),
);
setImageUrl(imageUrl);
const url = URL.createObjectURL(new Blob([imageBlob], { type: "image/png" }));
setImageUrl(url);
} catch (error) {
setError("Error fetching image");
console.error("Error fetching image:", error);
} finally {
currentRequests--;
activeRequests--;
processQueue();
}
};

const load = () => {
const requestImage = () => {
fetchImage();
};

queue.push(load);
requestQueue.push(requestImage);
processQueue();

return () => {
if (imageUrl) {
URL.revokeObjectURL(imageUrl);
}
};
}, [src, imageUrl]);

if (error) {
return <div>{error}</div>;
}
}, [src]);

return (
<div>{imageUrl ? <img src={imageUrl} alt={alt} /> : <p>Loading...</p>}</div>
<div>
{imageUrl ? <img src={imageUrl} alt={alt} /> : <p>Loading...</p>}
</div>
);
};

Expand Down
4 changes: 3 additions & 1 deletion example-web/react2/src/components/XPPotionsComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { CollectionConfigData } from "ps99-api";
import { GenericFetchComponent } from "./GenericFetchComponent";
import ImageComponent from "./ImageComponent";

const XPPotionsComponent: React.FC<{ configData?: CollectionConfigData<"XPPotions"> }> = ({ configData }) => {
const XPPotionsComponent: React.FC<{
configData?: CollectionConfigData<"XPPotions">;
}> = ({ configData }) => {
return (
<GenericFetchComponent<CollectionConfigData<"XPPotions">>
collectionName="XPPotions"
Expand Down
Loading

0 comments on commit bd700c5

Please sign in to comment.