Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion src/atlas_frontend/.astro/settings.json
Comment thread
Nyaxize marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"_variables": {
"lastUpdateCheck": 1753566875227
"lastUpdateCheck": 1755689594353
}
}
22 changes: 22 additions & 0 deletions src/atlas_frontend/src/canisters/atlasMain/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@ import { setConfig } from "../../store/slices/appSlice.js";
import { setSpaces } from "../../store/slices/spacesSlice.js";
import type { ExternalLinks } from "../atlasSpace/types.js";

const saveLastFetchTime = () => {
const now = new Date().toISOString();
localStorage.setItem("last_fetch_time", now);
};
Comment thread
Nyaxize marked this conversation as resolved.
Outdated

const getLastFetchTime = (): Date | null => {
const lastFetch = localStorage.getItem("last_fetch_time");
return lastFetch ? new Date(lastFetch) : null;
};

const shouldFetchSpaces = (): boolean => {
const lastFetchTime = getLastFetchTime();
if (!lastFetchTime) return true;

const now = new Date();
const diffMinutes = (now.getTime() - lastFetchTime.getTime()) / (1000 * 60);
return diffMinutes >= 5;
};

export { shouldFetchSpaces };
interface CreateNewSpaceArgs {
authAtlasMain: ActorSubclass<_SERVICE_MAIN>;
name: string;
Expand Down Expand Up @@ -84,6 +104,8 @@ export const getAllSpaces = async ({
unAuthAtlasMain,
dispatch,
}: GetAtlasData) => {
saveLastFetchTime();

let spacesCount = 0n;
let start = 0n;
const count = 200n;
Expand Down
36 changes: 19 additions & 17 deletions src/atlas_frontend/src/canisters/atlasSpace/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,26 @@ export const getAtlasSpace = async ({
}
const externalLinksObj = Object.fromEntries(state.external_links);

dispatch(
setSpace({
spaceId,
state: {
...state,
version,
space_symbol: state.space_symbol.pop() ?? null,
space_background: state.space_background.pop() ?? null,
space_logo: state.space_logo.pop() ?? null,
external_links: {
x: externalLinksObj?.x ?? null,
telegram: externalLinksObj?.telegram ?? null,
discord: externalLinksObj?.discord ?? null,
linkedIn: externalLinksObj?.linkedIn ?? null,
},
const spaceData = {
spaceId,
state: {
...state,
version,
space_symbol: state.space_symbol.pop() ?? null,
space_background: state.space_background.pop() ?? null,
space_logo: state.space_logo.pop() ?? null,
external_links: {
x: externalLinksObj?.x ?? null,
telegram: externalLinksObj?.telegram ?? null,
discord: externalLinksObj?.discord ?? null,
linkedIn: externalLinksObj?.linkedIn ?? null,
},
})
);
},
};

dispatch(setSpace(spaceData));

return spaceData;
};

interface CreateNewSpaceTaskArgs {
Expand Down
137 changes: 104 additions & 33 deletions src/atlas_frontend/src/components/Space/SpacesList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,129 @@ import {
useUnAuthAgent,
useUnAuthAtlasMainActor,
} from "../../../hooks/identityKit";
import { getAllSpaces } from "../../../canisters/atlasMain/api";
import { deserialize, type RootState } from "../../../store/store";
import {
getAllSpaces,
shouldFetchSpaces,
} from "../../../canisters/atlasMain/api";
import {
customSerify,
deserialize,
type RootState,
} from "../../../store/store";
import { Principal } from "@dfinity/principal";
import { getAtlasSpace } from "../../../canisters/atlasSpace/api";
import SpaceItem from "./SpaceItem";
import { useNavigate } from "react-router-dom";
import type { Spaces } from "../../../store/slices/spacesSlice";
import LocalBlurOverlay from "../../Shared/LocalBlurOverlay";
import { serify } from "@karmaniverous/serify-deserify";
import { setSpaces } from "../../../store/slices/spacesSlice";
import type { StorableState } from "../../../canisters/atlasSpace/types";

const syncSpacesWithLocalStorage = (reduxSpaces: Spaces) => {
try {
const savedData = localStorage.getItem("atlasSpaces");
const localSpaces = savedData ? JSON.parse(savedData) : {};
const reduxKeys = Object.keys(reduxSpaces || {});
const localKeys = Object.keys(localSpaces || {});

if (reduxKeys.length !== localKeys.length) {
const serializedData = JSON.stringify(
serify(reduxSpaces, customSerify)
);
localStorage.setItem("atlasSpaces", serializedData);
}
} catch (err) {
console.error("Failed to sync Redux spaces with localStorage:", err);
}
};
Comment thread
Nyaxize marked this conversation as resolved.
Outdated

const SpacesList = () => {
const dispatch = useDispatch();
const unAuthAtlasMain = useUnAuthAtlasMainActor();
const spaces = deserialize<Spaces>(useSelector((state: RootState) => state.spaces.spaces));
const [fetchedSpacesData, setFetchedSpacesData] = useState(false);
const [fetchingInProgress, setFetchingInProgress] = useState(true);
const spaces = deserialize<Spaces>(
useSelector((state: RootState) => state.spaces.spaces)
);

const [, setFetchingInProgress] = useState(true);
const agent = useUnAuthAgent();
const navigate = useNavigate();

useEffect(() => {
const fetchSpaces = async () => {
if (unAuthAtlasMain && !spaces) {
await getAllSpaces({
const loadAndFetchSpaces = async () => {
if (spaces && Object.keys(spaces).length > 1) {
setFetchingInProgress(false);
return;
}

setFetchingInProgress(true);
try {
const savedData = localStorage.getItem("atlasSpaces");
if (savedData) {
const loadedSpaces = JSON.parse(savedData);
if (loadedSpaces && Object.keys(loadedSpaces).length > 0) {
dispatch(setSpaces(loadedSpaces));
setFetchingInProgress(false);
return;
}
}
} catch (error) {
console.error("Failed to load spaces data from localStorage:", error);
}
if (unAuthAtlasMain && agent && shouldFetchSpaces()) {
const spacesIDs = await getAllSpaces({
dispatch,
unAuthAtlasMain,
});
setFetchingInProgress(false);
const updatedSpacesData: {
[key: string]: { state: StorableState | null; tasks: null };
} = {};
const spaceIds = Object.keys(spacesIDs);

for (const spaceId of spaceIds) {
const spacePrincipal = Principal.from(spaceId);
const unAuthAtlasSpace = getUnAuthAtlasSpaceActor(
agent,
spacePrincipal
);
if (!unAuthAtlasSpace) continue;

const spaceData = await getAtlasSpace({
spaceId,
unAuthAtlasSpace,
dispatch,
});

if (spaceData) {
updatedSpacesData[spaceId] = {
state: spaceData.state,
tasks: null,
};
}
}

if (Object.keys(updatedSpacesData).length > 0) {
dispatch(setSpaces(updatedSpacesData));
try {
const serializedData = JSON.stringify(
serify(updatedSpacesData, customSerify)
);
localStorage.setItem("atlasSpaces", serializedData);
} catch (error) {
console.error("Failed to save spaces data to localStorage:", error);
}
}
}
Comment thread
Nyaxize marked this conversation as resolved.
Outdated
setFetchingInProgress(false);
};
fetchSpaces();
}, [dispatch, unAuthAtlasMain]);

useEffect(() => {
if (!spaces || fetchedSpacesData || !agent) return;
Object.keys(spaces).map(async (spaceId) => {
const spacePrincipal = Principal.from(spaceId);
getUnAuthAtlasSpaceActor(agent, spacePrincipal);
const unAuthAtlasSpace = getUnAuthAtlasSpaceActor(agent, spacePrincipal);
if (!unAuthAtlasSpace) return;
await getAtlasSpace({
spaceId,
unAuthAtlasSpace,
dispatch,
});
});
setFetchedSpacesData(true);
}, [dispatch, spaces, fetchedSpacesData]);
loadAndFetchSpaces();

if (spaces && Object.keys(spaces).length > 0) {
syncSpacesWithLocalStorage(spaces);
}
}, [dispatch, unAuthAtlasMain, agent]);

if (!spaces) {
if (!fetchingInProgress) navigate("/");
return (
<LocalBlurOverlay isLoading={true} />
)
return <LocalBlurOverlay isLoading={true} />;
}

const spacesEntries = Object.entries(spaces);
Expand Down Expand Up @@ -89,4 +160,4 @@ const SpacesList = () => {
}
};

export default SpacesList;
export default SpacesList;