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/react": "18.0.27",
"@types/react-dom": "18.0.10",
"chart.js": "^4.2.1",
"eslint": "8.33.0",
"eslint-config-next": "13.1.6",
"next": "13.1.6",
"react": "18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "18.2.0",
"sqlite": "^4.1.2",
"sqlite3": "^5.1.4",
@ -97,6 +99,11 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
"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": {
"version": "1.0.10",
"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"
}
},
"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": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@ -4230,6 +4248,15 @@
"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": {
"version": "18.2.0",
"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",
"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": {
"version": "1.0.10",
"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"
}
},
"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": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@ -8144,6 +8184,12 @@
"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": {
"version": "18.2.0",
"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/react": "18.0.27",
"@types/react-dom": "18.0.10",
"chart.js": "^4.2.1",
"eslint": "8.33.0",
"eslint-config-next": "13.1.6",
"next": "13.1.6",
"react": "18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "18.2.0",
"sqlite": "^4.1.2",
"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 CardLayout from "../Layouts/CardLayout";
@ -7,9 +7,18 @@ const InventoryItem = (props: {
stakes: IStake[] | null;
upgradeInventoryItem: (itemId: number) => void;
}) => {
const getCurrentTier = (index: number) => {
return props.inventoryItem.storeItem.upgrades[index].tier;
};
const [currentTierIndex, setCurrentTierIndex] = useState(
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 = () => {
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 (
<CardLayout>
<h3 className="text-xl font-bold mb-2">
{props.inventoryItem.storeItem.name}{" "}
<span className="bg-green-600 rounded-full px-2">
{getCurrentTier(props.inventoryItem.currentTierIndex)}
</span>
{props.inventoryItem.storeItem.name}
<div className="flex">
{props.inventoryItem.storeItem.upgrades.map((upgrade, id) => {
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>
<p className="text-sm">{props.inventoryItem.storeItem.description}</p>
<div className="flex gap-4">
<div className="flex-1">
<p className="font-bold mt-4">Yield</p>
<ul className="list-none">
{getCurrentTier(props.inventoryItem.currentTierIndex)}
</ul>
<p>
{props.inventoryItem.storeItem.claimAmount} +{" "}
{currentUpgrade.claimBoost}
</p>
<ul className="list-none"></ul>
</div>
<div className="flex-1">
<div className="flex">
{/* { Check if the item is in use } */}
<div className="flex-1 text-center">
<p className="text-lg font-bold mb-2">{getNextUpgradePrice()}</p>
<div className="">
{isInUse() ? (
<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

View File

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

View File

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

View File

@ -2,6 +2,7 @@
import React, { useState } from "react";
import { IStoreItem } from "typings";
import CommonCardLayout from "../Layouts/CommonCardLayout";
import Chart from "./Chart";
const StoreItem = (props: {
storeItem: IStoreItem;
@ -9,7 +10,7 @@ const StoreItem = (props: {
}) => {
return (
<CommonCardLayout>
<div className="flex gap-4">
<div className="flex">
<div className="flex-1">
{props.storeItem.isOwned ? (
<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>
<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">Tier Upgrades</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>
<p className="font-bold mt-3">Base Yield</p>
<p className="">{props.storeItem.claimAmount}</p>
</div>
<div className="flex items-center h-100">
<div className="flex-none items-start h-100 text-center">
{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">
Owned
</button>
) : (
<>
<p className="text-lg font-bold mb-2">${props.storeItem.price}</p>
<button
onClick={() => props.buyStoreItem(props.storeItem.id)}
className="bg-slate-100 text-slate-900 px-4 py-2 rounded-lg font-bold w-28 text-center"
>
Buy
</button>
</>
)}
</div>
</div>
<p className="font-bold mt-3">Upgrades</p>
<div className="max-h-44">
<Chart upgrades={props.storeItem.upgrades} />
</div>
</CommonCardLayout>
);
};

View File

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

View File

@ -4,10 +4,8 @@ export default function CommonCardLayout({
children: React.ReactNode;
}) {
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}
</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;
}
export interface IUpgrade {
tier: number;
price: number;
claimBoost: number;
}
export interface IStoreItem {
id: string;
name: string;
@ -49,11 +55,7 @@ export interface IStoreItem {
price: number;
completionTimeInMins: number;
claimAmount: number;
upgrades: {
tier: number;
price: number;
claimBoost: number;
}[];
upgrades: IUpgrade[];
isOwned: boolean;
}
@ -140,3 +142,9 @@ export interface ISelectDropdownProps {
onChange?: (value: string) => void;
isActive: boolean
}
export interface IChart {
label: string
labels: string[]
values: number[]
}