refactor to use gameConfig from endpoint

This commit is contained in:
Emil Nielsen 2023-04-15 09:54:46 +07:00
parent 2f809bf889
commit 0668895422
17 changed files with 101 additions and 94 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 417 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 KiB

View File

Before

Width:  |  Height:  |  Size: 482 KiB

After

Width:  |  Height:  |  Size: 482 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

View File

Before

Width:  |  Height:  |  Size: 374 KiB

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

View File

@ -1,28 +1,41 @@
"use client"; "use client";
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { IResourceAccount, IConversionPair } from "typings"; import { IResourceAccount, IConversionPair, IGameConfig } from "typings";
import { resourceToFc } from "../../../utils/helpers"; import { resourceToFc } from "../../../utils/helpers";
import ResourceModal from "./ResourceModal"; import ResourceModal from "./ResourceModal";
const ResourceAccount = (props: { const ResourceAccount = (props: {
account: IResourceAccount; account: IResourceAccount;
sellResource: (pairs: IConversionPair[]) => void; sellResource: (pairs: IConversionPair[]) => void;
gameConfig: IGameConfig | undefined;
}) => { }) => {
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);
const [conversionPair, setConversionPair] = useState< const [conversionPair, setConversionPair] = useState<
IConversionPair | undefined IConversionPair | undefined
>(undefined); >(undefined);
const [conversionRate, setConversionRate] = useState<Number>(0.1); const [conversionRate, setConversionRate] = useState<number>(0.1);
const handleConversionPair = (amount: number, resourceType: string) => { const handleConversionPair = (amount: number, resourceType: string) => {
const updatedPair = { const updatedPair = {
resourceType: resourceType, resourceType: resourceType,
resourceAmount: amount, resourceAmount: amount,
moneyAmount: amount * conversionRate.valueOf(), moneyAmount: amount * conversionRate,
}; };
setConversionPair(updatedPair); setConversionPair(updatedPair);
}; };
const getConversionRate = (account: IResourceAccount) => {
if (props.gameConfig === undefined) return 0;
const query = account.resourceType + "ToMoonbucks";
const rate = props.gameConfig.gameConstants[query];
return rate;
};
useEffect(() => {
const rate = getConversionRate(props.account);
setConversionRate(rate);
}, [props.gameConfig]);
return ( return (
<> <>
{showModal && ( {showModal && (

View File

@ -1,12 +1,18 @@
"use client"; "use client";
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { IBankAccount, IConversionPair } from "typings"; import {
IBankAccount,
IConversionPair,
IGameConfig,
IResourceAccount,
} from "typings";
import Account from "./Account"; import Account from "./Account";
import { BiLoaderAlt } from "react-icons/bi"; import { BiLoaderAlt } from "react-icons/bi";
const BankAccountsView = (props: { const BankAccountsView = (props: {
bankAccount: IBankAccount | undefined; bankAccount: IBankAccount | undefined;
sellResource: (pairs: IConversionPair[]) => void; sellResource: (pairs: IConversionPair[]) => void;
gameConfig: IGameConfig | undefined;
}) => { }) => {
if (props.bankAccount === undefined) { if (props.bankAccount === undefined) {
return ( return (
@ -39,6 +45,7 @@ const BankAccountsView = (props: {
key={id} key={id}
account={account} account={account}
sellResource={props.sellResource} sellResource={props.sellResource}
gameConfig={props.gameConfig}
/> />
); );
})} })}

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { IInventoryItem, IStake } from "typings"; import { IInventoryItem, IStake, IUpgrade } from "typings";
import CardLayout from "../../Layouts/CardLayout"; import CardLayout from "../../Layouts/CardLayout";
import Image from "next/image"; import Image from "next/image";
const InventoryItem = (props: { const InventoryItem = (props: {
@ -10,14 +10,13 @@ const InventoryItem = (props: {
const [currentTierIndex, setCurrentTierIndex] = useState( const [currentTierIndex, setCurrentTierIndex] = useState(
props.inventoryItem.currentTierIndex props.inventoryItem.currentTierIndex
); );
const [currentUpgrade, setCurrentUpgrade] = useState( const [currentUpgrade, setCurrentUpgrade] = useState<IUpgrade | null>(null);
props.inventoryItem.storeItem.upgrades[currentTierIndex]
);
useEffect(() => { useEffect(() => {
const index = props.inventoryItem.currentTierIndex; const index = props.inventoryItem.currentTierIndex;
setCurrentTierIndex(index); setCurrentTierIndex(index);
setCurrentUpgrade(props.inventoryItem.storeItem.upgrades[index]); const currentUpdade = props.inventoryItem.storeItem.upgrades[index];
setCurrentUpgrade(currentUpdade);
}, [props.inventoryItem]); }, [props.inventoryItem]);
const isInUse = () => { const isInUse = () => {
@ -47,18 +46,21 @@ const InventoryItem = (props: {
<p>{props.inventoryItem.storeItem.claimAmount}</p> <p>{props.inventoryItem.storeItem.claimAmount}</p>
<p className="font-bold mb-1 mt-4">Tier</p> <p className="font-bold mb-1 mt-4">Tier</p>
<div className="flex items-center"> <div className="flex items-center">
{props.inventoryItem.storeItem.upgrades.map((upgrade, id) => { {currentUpgrade &&
if (upgrade.tier <= currentUpgrade.tier) { props.inventoryItem.storeItem.upgrades.map((upgrade, id) => {
return ( if (upgrade.tier <= currentUpgrade.tier) {
<span key={id} className="bg-green-600 px-4 py-2"></span> return (
); <span key={id} className="bg-green-600 px-4 py-2"></span>
} else { );
return ( } else {
<span key={id} className="bg-slate-200 px-4 py-2"></span> return (
); <span key={id} className="bg-slate-200 px-4 py-2"></span>
} );
})} }
<p className="font-bold ml-1">(+{currentUpgrade.claimBoost})</p> })}
<p className="font-bold ml-1">
(+{currentUpgrade && currentUpgrade.claimBoost})
</p>
</div> </div>
<p className="font-bold mb-1 mt-4">Upgrade</p> <p className="font-bold mb-1 mt-4">Upgrade</p>
<div className="flex items-center"> <div className="flex items-center">
@ -97,7 +99,7 @@ const InventoryItem = (props: {
</div> </div>
<div className="relative object-contain w-48 h-48 mt-4 md:mt-0"> <div className="relative object-contain w-48 h-48 mt-4 md:mt-0">
<Image <Image
src={props.inventoryItem.storeItem.image} src={"/assets/items/" + props.inventoryItem.storeItem.image}
alt={props.inventoryItem.storeItem.name} alt={props.inventoryItem.storeItem.name}
fill fill
className="rounded-lg border border-white/20 shadow-lg object-contain" className="rounded-lg border border-white/20 shadow-lg object-contain"

View File

@ -3,44 +3,6 @@ import React from "react";
import { IInventoryItem, IStakingSource } from "typings"; import { IInventoryItem, IStakingSource } from "typings";
import StakingSource from "./StakingSource"; import StakingSource from "./StakingSource";
const moons = [
{
name: "Caelusium",
description:
"Caelusium is a medium-sized moon with a diverse landscape. Its craters contain a wealth of common resources, making it an ideal starting location for beginners. The moon's relatively mild weather conditions and stable surface offer a friendly environment for establishing mining operations.",
image: "/assets/moon_1.png",
price: 100,
},
{
name: "Caelusium",
description:
"Caelusium is a medium-sized moon with a diverse landscape. Its craters contain a wealth of common resources, making it an ideal starting location for beginners. The moon's relatively mild weather conditions and stable surface offer a friendly environment for establishing mining operations.",
image: "/assets/moon_2.png",
price: 100,
},
{
name: "Caelusium",
description:
"Caelusium is a medium-sized moon with a diverse landscape. Its craters contain a wealth of common resources, making it an ideal starting location for beginners. The moon's relatively mild weather conditions and stable surface offer a friendly environment for establishing mining operations.",
image: "/assets/moon_3.png",
price: 100,
},
{
name: "Caelusium",
description:
"Caelusium is a medium-sized moon with a diverse landscape. Its craters contain a wealth of common resources, making it an ideal starting location for beginners. The moon's relatively mild weather conditions and stable surface offer a friendly environment for establishing mining operations.",
image: "/assets/moon_4.png",
price: 100,
},
{
name: "Caelusium",
description:
"Caelusium is a medium-sized moon with a diverse landscape. Its craters contain a wealth of common resources, making it an ideal starting location for beginners. The moon's relatively mild weather conditions and stable surface offer a friendly environment for establishing mining operations.",
image: "/assets/moon_5.png",
price: 100,
},
];
interface RowProps { interface RowProps {
stakingSources: IStakingSource[]; stakingSources: IStakingSource[];
inventoryItems: IInventoryItem[] | undefined | null; inventoryItems: IInventoryItem[] | undefined | null;

View File

@ -39,7 +39,7 @@ const StoreItem = (props: {
</div> </div>
<div className="relative object-contain w-48 h-48"> <div className="relative object-contain w-48 h-48">
<Image <Image
src={props.storeItem.image} src={"/assets/items/" + props.storeItem.image}
alt={props.storeItem.name} alt={props.storeItem.name}
fill fill
className="rounded-lg border border-white/20 shadow-lg object-contain mt-4 md:mt-0" className="rounded-lg border border-white/20 shadow-lg object-contain mt-4 md:mt-0"

View File

@ -4,7 +4,7 @@ import StoreItem from "./StoreItem";
const StoreItemView = (props: { const StoreItemView = (props: {
inventoryItems: IInventoryItem[] | null | undefined; inventoryItems: IInventoryItem[] | null | undefined;
storeItems: IStoreItem[]; storeItems: IStoreItem[] | null;
buyStoreItem: (storeItemId: number) => void; buyStoreItem: (storeItemId: number) => void;
}) => { }) => {
return ( return (
@ -12,15 +12,16 @@ const StoreItemView = (props: {
<div className="bg-slate-900 text-white p-8 rounded-xl h-full"> <div className="bg-slate-900 text-white p-8 rounded-xl h-full">
<h2 className="text-3xl font-bold mb-4 text-white">Store</h2> <h2 className="text-3xl font-bold mb-4 text-white">Store</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8"> <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{props.storeItems {props.storeItems &&
.filter((item) => !item.isOwned) props.storeItems
.map((storeItem, id) => ( .filter((item) => !item.isOwned)
<StoreItem .map((storeItem, id) => (
key={id} <StoreItem
storeItem={storeItem} key={id}
buyStoreItem={props.buyStoreItem} storeItem={storeItem}
/> buyStoreItem={props.buyStoreItem}
))} />
))}
</div> </div>
</div> </div>
</div> </div>

View File

@ -5,7 +5,6 @@ import StakingSourcesView from "./Components/Staking/StakingSourcesView";
import BankAccountsView from "./Components/Accounts/AccountsView"; import BankAccountsView from "./Components/Accounts/AccountsView";
import StoreItemView from "./Components/Store/StoreItemView"; import StoreItemView from "./Components/Store/StoreItemView";
import NotificationPopover from "./Components/NotificationPopover"; import NotificationPopover from "./Components/NotificationPopover";
import { gameConfig } from "@/utils/gameLogic";
import { import {
IInventoryItem, IInventoryItem,
IStakingSource, IStakingSource,
@ -13,6 +12,8 @@ import {
IStake, IStake,
IConversionPair, IConversionPair,
Notification, Notification,
IGameConfig,
IStoreItem,
} from "typings"; } from "typings";
import Navbar from "./Components/Navigation/Navbar"; import Navbar from "./Components/Navigation/Navbar";
import NavbarVertical from "./Components/Navigation/NavbarVertical"; import NavbarVertical from "./Components/Navigation/NavbarVertical";
@ -26,13 +27,13 @@ export default function Home() {
); );
const [bankAccount, setBankAccount] = useState<IBankAccount>(); const [bankAccount, setBankAccount] = useState<IBankAccount>();
const [userStakes, setUserStakes] = useState<IStake[]>([]); const [userStakes, setUserStakes] = useState<IStake[]>([]);
const [lightBoxIsActive, setLightBoxIsActive] = useState(false);
const [userId, setUserId] = useState<string>(""); const [userId, setUserId] = useState<string>("");
const [notification, setNotification] = useState<Notification | null>(null); const [notification, setNotification] = useState<Notification | null>(null);
const [notificationTime, setNotificationTime] = useState(30); const [notificationTime, setNotificationTime] = useState(30);
const [storeItems, setStoreItems] = useState(gameConfig.store); const [storeItems, setStoreItems] = useState<IStoreItem[] | null>(null);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [activeComponent, setActiveComponent] = useState("stakingsourcesview"); const [activeComponent, setActiveComponent] = useState("inventoryitemview");
const [gameConfig, setGameConfig] = useState<IGameConfig>();
const isOwned = (storeItemId: number) => { const isOwned = (storeItemId: number) => {
if (inventoryItems && inventoryItems?.length > 0) { if (inventoryItems && inventoryItems?.length > 0) {
@ -46,20 +47,34 @@ export default function Home() {
const response = await fetch(`/api/user/${userId}/inventory-items`); const response = await fetch(`/api/user/${userId}/inventory-items`);
const DBInventoryItems = await response.json(); const DBInventoryItems = await response.json();
for (const invItem of DBInventoryItems.inventoryItems) { // Calling the endpoint here because state might not be ready
invItem.storeItem = gameConfig.store.find( const gameConfig = await fetch(`/api/get-game-config`);
(item) => item.id === invItem.storeItemId const gameConfigData = await gameConfig.json();
);
} const updatedInventoryItems = DBInventoryItems.inventoryItems.map(
// TODO Can you just return the array? (invItem: IInventoryItem) => {
console.log(DBInventoryItems.inventoryItems); return {
setInventoryItems(DBInventoryItems.inventoryItems); ...invItem,
storeItem: gameConfigData.storeItems?.find(
(item: IStoreItem) => item.id === invItem.storeItemId
),
};
}
);
setInventoryItems(updatedInventoryItems);
};
const fetchStoreItems = async () => {
const response = await fetch(`/api/get-game-config`);
const data = await response.json();
setGameConfig(data);
setStoreItems(data.storeItems);
}; };
const fetchStakingSources = async () => { const fetchStakingSources = async () => {
const response = await fetch(`/api/user/${userId}/staking-sources`); const response = await fetch(`/api/user/${userId}/staking-sources`);
const sources = await response.json(); const sources = await response.json();
// TODO Can you just return the array?
setStakingSources(sources.stakingSources); setStakingSources(sources.stakingSources);
}; };
@ -86,21 +101,23 @@ export default function Home() {
fetchStakingSources(); fetchStakingSources();
fetchInventoryItems(); fetchInventoryItems();
fetchStakes(); fetchStakes();
fetchStoreItems();
setIsLoading(false); setIsLoading(false);
}, [userId]); }, [userId]);
// Update data // Update data
useEffect(() => { useEffect(() => {
const updatedStoreItems = storeItems.map((storeItem) => { if (storeItems) {
return { const updatedStoreItems = storeItems.map((storeItem) => {
...storeItem, return {
isOwned: isOwned(storeItem.id), ...storeItem,
}; isOwned: isOwned(storeItem.id),
}); };
updatedStoreItems && setStoreItems(updatedStoreItems); });
updatedStoreItems && setStoreItems(updatedStoreItems);
}
}, [inventoryItems]); }, [inventoryItems]);
// Hide error automatically
useEffect(() => { useEffect(() => {
if (notification) { if (notification) {
const intervalId = setInterval(() => { const intervalId = setInterval(() => {
@ -332,7 +349,11 @@ export default function Home() {
onClose={handleCloseNotification} onClose={handleCloseNotification}
/> />
)} )}
<BankAccountsView bankAccount={bankAccount} sellResource={sellResource} /> <BankAccountsView
bankAccount={bankAccount}
sellResource={sellResource}
gameConfig={gameConfig}
/>
<div className="grid grid-cols-1 md:grid-cols-6 p-4 gap-8"> <div className="grid grid-cols-1 md:grid-cols-6 p-4 gap-8">
<NavbarVertical <NavbarVertical
onMenuItemClick={handleMenuItemClick} onMenuItemClick={handleMenuItemClick}

1
typings.d.ts vendored
View File

@ -83,6 +83,7 @@ export interface IGameConfig {
resources: string[]; resources: string[];
[key: string]: any; [key: string]: any;
store: IStoreItem[]; store: IStoreItem[];
gameConstants: {[key: string]: any;}
} }
export interface IConversionPair { export interface IConversionPair {