Add chart.js, modify StoreItems

This commit is contained in:
Emil Nielsen 2023-03-23 19:55:57 +07:00
parent a5c2ebb0ea
commit 16eb1405e6
10 changed files with 238 additions and 66 deletions

46
package-lock.json generated
View File

@ -13,10 +13,12 @@
"@types/node": "18.13.0", "@types/node": "18.13.0",
"@types/react": "18.0.27", "@types/react": "18.0.27",
"@types/react-dom": "18.0.10", "@types/react-dom": "18.0.10",
"chart.js": "^4.2.1",
"eslint": "8.33.0", "eslint": "8.33.0",
"eslint-config-next": "13.1.6", "eslint-config-next": "13.1.6",
"next": "13.1.6", "next": "13.1.6",
"react": "18.2.0", "react": "18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"sqlite": "^4.1.2", "sqlite": "^4.1.2",
"sqlite3": "^5.1.4", "sqlite3": "^5.1.4",
@ -97,6 +99,11 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
}, },
"node_modules/@kurkle/color": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
},
"node_modules/@mapbox/node-pre-gyp": { "node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz",
@ -1238,6 +1245,17 @@
"url": "https://github.com/chalk/chalk?sponsor=1" "url": "https://github.com/chalk/chalk?sponsor=1"
} }
}, },
"node_modules/chart.js": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.2.1.tgz",
"integrity": "sha512-6YbpQ0nt3NovAgOzbkSSeeAQu/3za1319dPUQTXn9WcOpywM8rGKxJHrhS8V8xEkAlk8YhEfjbuAPfUyp6jIsw==",
"dependencies": {
"@kurkle/color": "^0.3.0"
},
"engines": {
"pnpm": "^7.0.0"
}
},
"node_modules/chokidar": { "node_modules/chokidar": {
"version": "3.5.3", "version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@ -4230,6 +4248,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-chartjs-2": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz",
"integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==",
"peerDependencies": {
"chart.js": "^4.1.1",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "18.2.0", "version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
@ -5290,6 +5317,11 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
}, },
"@kurkle/color": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
},
"@mapbox/node-pre-gyp": { "@mapbox/node-pre-gyp": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz",
@ -6030,6 +6062,14 @@
"supports-color": "^7.1.0" "supports-color": "^7.1.0"
} }
}, },
"chart.js": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.2.1.tgz",
"integrity": "sha512-6YbpQ0nt3NovAgOzbkSSeeAQu/3za1319dPUQTXn9WcOpywM8rGKxJHrhS8V8xEkAlk8YhEfjbuAPfUyp6jIsw==",
"requires": {
"@kurkle/color": "^0.3.0"
}
},
"chokidar": { "chokidar": {
"version": "3.5.3", "version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@ -8144,6 +8184,12 @@
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
} }
}, },
"react-chartjs-2": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz",
"integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==",
"requires": {}
},
"react-dom": { "react-dom": {
"version": "18.2.0", "version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",

View File

@ -14,10 +14,12 @@
"@types/node": "18.13.0", "@types/node": "18.13.0",
"@types/react": "18.0.27", "@types/react": "18.0.27",
"@types/react-dom": "18.0.10", "@types/react-dom": "18.0.10",
"chart.js": "^4.2.1",
"eslint": "8.33.0", "eslint": "8.33.0",
"eslint-config-next": "13.1.6", "eslint-config-next": "13.1.6",
"next": "13.1.6", "next": "13.1.6",
"react": "18.2.0", "react": "18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"sqlite": "^4.1.2", "sqlite": "^4.1.2",
"sqlite3": "^5.1.4", "sqlite3": "^5.1.4",

View File

@ -0,0 +1,99 @@
import React from "react";
import { useState, useEffect } from "react";
import { Line } from "react-chartjs-2";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
Filler,
BarElement,
ArcElement,
} from "chart.js";
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
BarElement,
ArcElement,
Title,
Tooltip,
Legend,
Filler
);
import { IChart, IUpgrade } from "typings";
// https://www.chartjs.org/docs/latest/samples/scale-options/grid.html
const Chart = (props: { upgrades: IUpgrade[] }) => {
const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: "bottom" as const,
},
title: {
display: false,
},
},
scales: {
x: {
grid: {
display: false,
},
},
},
};
const [chartData, setChartData] = useState({
labels: props.upgrades.map((upgrade) => `$${upgrade.price}`),
datasets: [
{
label: "Upgrades",
backgroundColor: "rgb(242, 244, 250, 1)",
data: props.upgrades.map((upgrade) => upgrade.claimBoost),
tension: 0.3,
borderWidth: 2,
pointRadius: 4,
pointHoverRadius: 10,
borderColor: "rgb(52, 152, 219)",
fill: {
target: "origin",
above: "rgba(52, 152, 219, 0.05)",
},
},
],
});
/* useEffect(() => {
setChartData({
labels: labels,
datasets: {
label: label,
backgroundColor: "rgb(242, 244, 250, 1)",
data: values,
tension: 0.3,
borderWidth: 5,
pointRadius: 7,
pointHoverRadius: 10,
borderColor: "rgb(52, 152, 219)",
fill: {
target: "origin",
above: "rgba(52, 152, 219, 0.05)",
},
},
});
}, [values]); */
return <Line options={options} data={chartData} />;
};
export default Chart;

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useState, useEffect } from "react";
import { IInventoryItem, IStake } from "typings"; import { IInventoryItem, IStake } from "typings";
import CardLayout from "../Layouts/CardLayout"; import CardLayout from "../Layouts/CardLayout";
@ -7,9 +7,18 @@ const InventoryItem = (props: {
stakes: IStake[] | null; stakes: IStake[] | null;
upgradeInventoryItem: (itemId: number) => void; upgradeInventoryItem: (itemId: number) => void;
}) => { }) => {
const getCurrentTier = (index: number) => { const [currentTierIndex, setCurrentTierIndex] = useState(
return props.inventoryItem.storeItem.upgrades[index].tier; props.inventoryItem.currentTierIndex
}; );
const [currentUpgrade, setCurrentUpgrade] = useState(
props.inventoryItem.storeItem.upgrades[currentTierIndex]
);
useEffect(() => {
const index = props.inventoryItem.currentTierIndex;
setCurrentTierIndex(index);
setCurrentUpgrade(props.inventoryItem.storeItem.upgrades[index]);
}, [props.inventoryItem]);
const isInUse = () => { const isInUse = () => {
if (!props.stakes) return false; if (!props.stakes) return false;
@ -18,25 +27,49 @@ const InventoryItem = (props: {
}); });
}; };
const getNextUpgradePrice = () => {
if (currentTierIndex === 4) return "Maxed";
return `$${
props.inventoryItem.storeItem.upgrades[currentTierIndex + 1].price
}`;
};
return ( return (
<CardLayout> <CardLayout>
<h3 className="text-xl font-bold mb-2"> <h3 className="text-xl font-bold mb-2">
{props.inventoryItem.storeItem.name}{" "} {props.inventoryItem.storeItem.name}
<span className="bg-green-600 rounded-full px-2"> <div className="flex">
{getCurrentTier(props.inventoryItem.currentTierIndex)} {props.inventoryItem.storeItem.upgrades.map((upgrade, id) => {
</span> if (upgrade.tier <= currentUpgrade.tier) {
return (
<span
key={id}
className="bg-green-600 px-2 py-2 border border-black"
></span>
);
} else {
return (
<span
key={id}
className="bg-slate-200 px-2 py-2 border border-black"
></span>
);
}
})}
</div>
</h3> </h3>
<p className="text-sm">{props.inventoryItem.storeItem.description}</p> <p className="text-sm">{props.inventoryItem.storeItem.description}</p>
<div className="flex gap-4"> <div className="flex gap-4">
<div className="flex-1"> <div className="flex-1">
<p className="font-bold mt-4">Yield</p> <p className="font-bold mt-4">Yield</p>
<ul className="list-none"> <p>
{getCurrentTier(props.inventoryItem.currentTierIndex)} {props.inventoryItem.storeItem.claimAmount} +{" "}
</ul> {currentUpgrade.claimBoost}
</p>
<ul className="list-none"></ul>
</div> </div>
<div className="flex-1"> <div className="flex-1 text-center">
<div className="flex"> <p className="text-lg font-bold mb-2">{getNextUpgradePrice()}</p>
{/* { Check if the item is in use } */} <div className="">
{isInUse() ? ( {isInUse() ? (
<button className="bg-slate-400 text-slate-600 px-4 py-2 rounded-lg font-bold w-28 text-center cursor-not-allowed"> <button className="bg-slate-400 text-slate-600 px-4 py-2 rounded-lg font-bold w-28 text-center cursor-not-allowed">
In Use In Use

View File

@ -134,10 +134,6 @@ const StakingSource = (props: {
<span className="font-bold">Stake amount: </span> <span className="font-bold">Stake amount: </span>
{stake.stakeAmount} {stake.stakeAmount}
</p> </p>
<p>
<span className="font-bold">Start Time:</span>{" "}
{stake.startTime}
</p>
<RenderButtonOrCountdown stake={stake} /> <RenderButtonOrCountdown stake={stake} />
</div> </div>
))} ))}

View File

@ -9,8 +9,6 @@ const StakingSourcesView = (props: {
claimStake: (stakingEventId: number) => void; claimStake: (stakingEventId: number) => void;
startStake: (inventoryItemId: number, wellId: number) => void; startStake: (inventoryItemId: number, wellId: number) => void;
}) => { }) => {
console.log(props.inventoryItems);
console.log(props.stakingSources);
return ( return (
<div className="bg-slate-800 p-4 rounded-lg text-white"> <div className="bg-slate-800 p-4 rounded-lg text-white">
<h2 className="text-2xl mb-4 font-bold">Your Moons</h2> <h2 className="text-2xl mb-4 font-bold">Your Moons</h2>

View File

@ -2,6 +2,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { IStoreItem } from "typings"; import { IStoreItem } from "typings";
import CommonCardLayout from "../Layouts/CommonCardLayout"; import CommonCardLayout from "../Layouts/CommonCardLayout";
import Chart from "./Chart";
const StoreItem = (props: { const StoreItem = (props: {
storeItem: IStoreItem; storeItem: IStoreItem;
@ -9,7 +10,7 @@ const StoreItem = (props: {
}) => { }) => {
return ( return (
<CommonCardLayout> <CommonCardLayout>
<div className="flex gap-4"> <div className="flex">
<div className="flex-1"> <div className="flex-1">
{props.storeItem.isOwned ? ( {props.storeItem.isOwned ? (
<span className="text-green-600 font-bold">Owned</span> <span className="text-green-600 font-bold">Owned</span>
@ -18,42 +19,31 @@ const StoreItem = (props: {
)} )}
<h3 className="text-xl font-bold mb-2">{props.storeItem.name}</h3> <h3 className="text-xl font-bold mb-2">{props.storeItem.name}</h3>
<p className="text-sm mb-3">{props.storeItem.description}</p> <p className="text-sm mb-3">{props.storeItem.description}</p>
<p className="text-lg font-bold">$ {props.storeItem.price}</p> <p className="font-bold mt-3">Base Yield</p>
<p className="font-bold mt-3">Tier Upgrades</p> <p className="">{props.storeItem.claimAmount}</p>
<table className="table-auto text-center">
<tbody>
<tr>
<th className="border border-white py-1 px-3 w-18">Tier</th>
<th className="border border-white py-1 px-3 w-28">Price</th>
</tr>
{props.storeItem.upgrades.map((tier, id) => (
<tr key={id}>
<td className="border border-white py-1 px-3 w-18">
{tier.tier}
</td>
<td className="border border-white py-1 px-3 w-28">
${tier.price}
</td>
</tr>
))}
</tbody>
</table>
</div> </div>
<div className="flex items-center h-100"> <div className="flex-none items-start h-100 text-center">
{props.storeItem.isOwned ? ( {props.storeItem.isOwned ? (
<button className="bg-slate-400 text-slate-600 px-4 py-2 rounded-lg font-bold w-28 text-center cursor-not-allowed"> <button className="bg-slate-400 text-slate-600 px-4 py-2 rounded-lg font-bold w-28 text-center cursor-not-allowed">
Owned Owned
</button> </button>
) : ( ) : (
<button <>
onClick={() => props.buyStoreItem(props.storeItem.id)} <p className="text-lg font-bold mb-2">${props.storeItem.price}</p>
className="bg-slate-100 text-slate-900 px-4 py-2 rounded-lg font-bold w-28 text-center" <button
> onClick={() => props.buyStoreItem(props.storeItem.id)}
Buy className="bg-slate-100 text-slate-900 px-4 py-2 rounded-lg font-bold w-28 text-center"
</button> >
Buy
</button>
</>
)} )}
</div> </div>
</div> </div>
<p className="font-bold mt-3">Upgrades</p>
<div className="max-h-44">
<Chart upgrades={props.storeItem.upgrades} />
</div>
</CommonCardLayout> </CommonCardLayout>
); );
}; };

View File

@ -10,16 +10,18 @@ const StoreItemView = (props: {
return ( return (
<div className="bg-slate-800 p-4 rounded-lg"> <div className="bg-slate-800 p-4 rounded-lg">
<h2 className="text-2xl font-bold mb-4 text-white">Store</h2> <h2 className="text-2xl font-bold mb-4 text-white">Store</h2>
{props.storeItems && <div className="grid grid-cols-2 gap-4">
props.storeItems {props.storeItems &&
.sort((a, b) => (a.isOwned === b.isOwned ? 0 : a.isOwned ? 1 : -1)) props.storeItems
.map((storeItem, id) => ( .sort((a, b) => (a.isOwned === b.isOwned ? 0 : a.isOwned ? 1 : -1))
<StoreItem .map((storeItem, id) => (
key={id} <StoreItem
storeItem={storeItem} key={id}
buyStoreItem={props.buyStoreItem} storeItem={storeItem}
/> buyStoreItem={props.buyStoreItem}
))} />
))}
</div>
</div> </div>
); );
}; };

View File

@ -4,10 +4,8 @@ export default function CommonCardLayout({
children: React.ReactNode; children: React.ReactNode;
}) { }) {
return ( return (
<div className="rounded-lg border border-black/25 bg-gradient-to-br from-slate-700 via-slate-600 to-slate-800 shadow-xl shadow-black/5 p-4 mb-4 text-slate-100"> <div className="rounded-lg border border-black/25 bg-gradient-to-br from-slate-700 via-slate-600 to-slate-800 shadow-xl shadow-black/5 p-4 text-slate-100">
{children} {children}
</div> </div>
); );
} }
// rounded-lg border border-black/25 bg-gradient-to-br from-slate-700 via-slate-600 to-slate-800 shadow-xl shadow-black/5 p-4 mb-4 text-slate-100

18
typings.d.ts vendored
View File

@ -42,6 +42,12 @@ export interface IInventoryItem {
currentTierIndex: number; currentTierIndex: number;
} }
export interface IUpgrade {
tier: number;
price: number;
claimBoost: number;
}
export interface IStoreItem { export interface IStoreItem {
id: string; id: string;
name: string; name: string;
@ -49,11 +55,7 @@ export interface IStoreItem {
price: number; price: number;
completionTimeInMins: number; completionTimeInMins: number;
claimAmount: number; claimAmount: number;
upgrades: { upgrades: IUpgrade[];
tier: number;
price: number;
claimBoost: number;
}[];
isOwned: boolean; isOwned: boolean;
} }
@ -140,3 +142,9 @@ export interface ISelectDropdownProps {
onChange?: (value: string) => void; onChange?: (value: string) => void;
isActive: boolean isActive: boolean
} }
export interface IChart {
label: string
labels: string[]
values: number[]
}