Skip to content

Commit

Permalink
enhanced(ui): UI package extensions with components and calls in demo…
Browse files Browse the repository at this point in the history
…-game (#47)

* Adding dice as ui component

* added logo component

* Probability chart, tooltip missing, input could be extended

* fix css and Logo component

* generalize playerDisplay, Logo/Avatar

* adding xp bar

* Storage Overview adapting height size

* adjusted some todos for timeline entry

* timeline

* Trading

* adding price to trading form

* adding navbar

* sidebar structure

* remove duplicate style imports

* pin next peer dep in ui package

* remove redundant type in formik

* customize period and segment names in timeline entry

* remove redundant key reference in object

* add strings and booleans directly in components (here layout)

* direct inference of booleans in timeline entry

* some clean up

* remove hard-coded number of segments in timeline

* refining layout

* storage overview fallback if no images are provided

* rounded edges for avatar

* timeline admin prep

* change avatar to button

* providing react nodes for icons in storage overview

* trading form validation schema with yup

* TimelineEntry entryStatus, past, current and future

* adding segmentCount to periods in db and for fetching

* avoid spread syntax on accumulators

* providing types for achievements

* cleaning up rest of todos and comments for segment count and filtering

---------

Co-authored-by: Roland Schläfli <[email protected]>
  • Loading branch information
jajakob and rschlaefli authored Aug 12, 2024
1 parent 58fe5bf commit c964a36
Show file tree
Hide file tree
Showing 26 changed files with 995 additions and 682 deletions.
3 changes: 3 additions & 0 deletions apps/demo-game/src/graphql/generated/nexus-typegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export interface NexusGenObjects {
id: string; // ID!
index: number; // Int!
results: NexusGenRootTypes['PlayerResult'][]; // [PlayerResult!]!
segmentCount?: number | null; // Int
segments: NexusGenRootTypes['PeriodSegment'][]; // [PeriodSegment!]!
}
PeriodSegment: { // root type
Expand Down Expand Up @@ -314,6 +315,7 @@ export interface NexusGenFieldTypes {
id: string; // ID!
index: number; // Int!
results: NexusGenRootTypes['PlayerResult'][]; // [PlayerResult!]!
segmentCount: number | null; // Int
segments: NexusGenRootTypes['PeriodSegment'][]; // [PeriodSegment!]!
}
PeriodSegment: { // field return type
Expand Down Expand Up @@ -492,6 +494,7 @@ export interface NexusGenFieldTypeNames {
id: 'ID'
index: 'Int'
results: 'PlayerResult'
segmentCount: 'Int'
segments: 'PeriodSegment'
}
PeriodSegment: { // field return type name
Expand Down
6 changes: 4 additions & 2 deletions apps/demo-game/src/graphql/generated/ops.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions apps/demo-game/src/graphql/generated/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ type Period {
id: ID!
index: Int!
results: [PlayerResult!]!
segmentCount: Int
segments: [PeriodSegment!]!
}

Expand Down
12 changes: 12 additions & 0 deletions apps/demo-game/src/graphql/generated/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1509,6 +1509,18 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "segmentCount",
"description": null,
"args": [],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "segments",
"description": null,
Expand Down
232 changes: 184 additions & 48 deletions apps/demo-game/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,203 @@
// import { useQuery } from '@apollo/client'
import { faStar } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {
Layout,
PlayerDisplay,
ProbabilityChart,
StorageOverview,
Timeline,
TimelineAdmin,
TimelineEntry,
TradingForm,
} from '@gbl-uzh/ui'
// import { ResultDocument } from 'src/graphql/generated/ops'

import { useRouter } from 'next/router'

export default function Home() {
// const { data, loading, error } = useQuery(ResultDocument, {
// fetchPolicy: 'cache-first',
// })

// if (loading) return <div>Loading...</div>
// if (error) return <div>Error {error.message}</div>
// console.log(data)

const router = useRouter()
const tabs = [
{ name: 'Welcome', href: '/play/welcome' },
{ name: 'Cockpit', href: '/play/cockpit' },
]
const playerInfo = {
name: 'playerName',
color: 'Red',
location: 'ZH',
level: 1,
xp: 20,
xpMax: 50,
achievements: [],
imgPathAvatar: '/avatars/avatar_placeholder.png',
imgPathLocation: '/locations/ZH.svg',
onClick: () => {
router.replace('/play/welcome')
},
}
const storageInfo = {
storageTotal: 3,
storageUsed: 1,
icon: <FontAwesomeIcon icon={faStar} />,
// icon: <img src={'/cocoa_1.png'} />,
}
return (
<div className="font-source-sans p-4">
hello world
{/* <Button /> */}
{/* <Dice dice1={'dice1'} dice2={'dice2'} /> */}
{/* <Progress value={50} max={100} formatter={(val) => `${val}XP`} /> */}
<div className="flex w-1/3 flex-col">
<PlayerDisplay
name={'playerName'}
avatar={'avatar_placeholder'}
color={'Red'}
achievements={[]}
location={'ZH'}
xp={20}
xpToNext={50}
level={1}
onClick={() => {
router.replace('/play/welcome')
<div>
<Layout tabs={tabs} playerInfo={playerInfo} storageInfo={storageInfo}>
<div className="w-full rounded bg-black"></div>
</Layout>
<div className="font-source-sans p-4">
hello world
{/* <Dice dice1={6} dice2={6} /> */}
{/* <Progress value={50} max={100} formatter={(val) => `${val}XP`} /> */}
<div className="flex w-1/3 flex-col">
<PlayerDisplay {...playerInfo} />
<StorageOverview {...storageInfo} />
</div>
<ProbabilityChart trendE={5} trendGap={8} totalEyes={'12'} />
<TimelineEntry
periodIx={1}
segmentIx={1}
numSegments={2}
gameStatus="PERIOD_END"
entryStatus="CURRENT"
>
<div>Child</div>
</TimelineEntry>
<Timeline
// NOTE(JJ): Check the prisma schema what Period includes
periods={[
{
segments: [
{
index: 0,
facts: {
cashBalance: 3,
storageAmount: 6,
spotPrice: 1,
futuresPrice: 1,
},
},
{
index: 1,
facts: {
cashBalance: 3,
storageAmount: 6,
spotPrice: 2,
futuresPrice: 3,
},
},
],
segmentCount: 2,
index: 0,
facts: {
cashBalance: 3,
storageAmount: 6,
spotPrice: 2,
futuresPrice: 2,
},
},
]}
entries={[
{
id: 0,
type: 'PERIOD_START',
period: { id: 0, index: 0 },
segment: { id: 0, index: 0 },
facts: {
finalSpotPrice: 9,
},
},
{
id: 1,
type: 'SEGMENT_START',
period: { id: 0, index: 0 },
segment: { id: 0, index: 0 },
facts: {
finalSpotPrice: 9,
},
},
{
id: 2,
type: 'SEGMENT_END',
period: { id: 0, index: 0 },
segment: { id: 0, index: 0 },
facts: {
finalSpotPrice: 9,
},
},
{
id: 3,
type: 'SEGMENT_START',
period: { id: 0, index: 0 },
segment: { id: 1, index: 1 },
facts: {
finalSpotPrice: 9,
},
},
{
id: 4,
type: 'SEGMENT_END',
period: { id: 0, index: 0 },
segment: { id: 1, index: 1 },
facts: {
finalSpotPrice: 9,
},
},
]}
activePeriodIx={0}
activeSegmentIx={0}
formatter={(current, prev) => {
// Do computation here
const spotPrice =
current.segmentFlat?.facts.spotPrice ??
current.facts.finalSpotPrice
const futuresPrice =
current.segmentFlat?.facts.futuresPrice ??
current.facts.finalSpotPrice

const spotPriceDelta =
prev?.segmentFlat?.facts.spotPrice &&
(spotPrice / prev.segmentFlat.facts.spotPrice - 1) * 100

const futuresPriceDelta =
prev?.segmentFlat?.facts.futuresPrice &&
(futuresPrice / prev.segmentFlat.facts.futuresPrice - 1) * 100
return (
<>
{spotPriceDelta && <div>S {spotPriceDelta}</div>}
{futuresPriceDelta && <div>F {futuresPriceDelta}</div>}
</>
)
}}
/>
<StorageOverview
storageTotal={3}
storageUsed={1}
imgSrcTotal={'/avatars/cocoa_0.png'}
imgSrcUsed={'/avatars/cocoa_3.png'}
<TradingForm
price={10}
nameButtonBuy={'Buy'}
nameButtonSell={'Sell'}
onSubmit={async (values, helpers) => {
console.log(values)
// await performAction({
// variables: {
// type: ActionTypes.SPOT_TRADE,
// payload: JSON.stringify({
// volume: values.modifier * Number(values.volume),
// }),
// },
// })
helpers.resetForm()
}}
/>
<TimelineAdmin />
</div>
<ProbabilityChart trendE={5} trendGap={8} totalEyes={'12'} />
<TimelineEntry
periodIx={1}
segmentIx={1}
isCurrentEntry={true}
isPastEntry={false}
type={'PERIOD_END'}
cashBalance={1}
storageAmount={1}
/>
<Timeline
periods={[
{
segments: [{ index: 0 }],
index: 0,
facts: {
cashBalance: 1,
storageAmount: 1,
finalSpotprice: 1,
},
},
]}
entries={[{ type: 'PERIOD_START', period: { index: 0 }, segment: {} }]}
activePeriodIx={0}
activeSegmentIx={0}
/>
</div>
)
}
6 changes: 2 additions & 4 deletions apps/demo-game/src/pages/play/cockpit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,8 @@ function Cockpit() {
} else if (type == 'total') {
val = value.totalAssets
}
return {
...acc,
[value.ix]: val,
}
acc[value.ix] = val
return acc
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/platform/public/ops/QResult.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ query Result {
status
periods {
...PeriodData
segmentCount
}
activePeriod {
...PeriodData
Expand Down
23 changes: 22 additions & 1 deletion packages/platform/src/services/PlayService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ interface GetPlayerResultArgs {
}

export async function getPlayerResult(args: GetPlayerResultArgs, ctx: Context) {
const currentGame = await ctx.prisma.game.findUnique({
let currentGame = await ctx.prisma.game.findUnique({
where: {
id: args.gameId,
},
Expand Down Expand Up @@ -238,6 +238,27 @@ export async function getPlayerResult(args: GetPlayerResultArgs, ctx: Context) {

if (!currentGame?.activePeriod) return null

// The segementCount for active period is currently not needed
currentGame.periods = currentGame.periods.map((period) => ({
...period,
segmentCount: period.segments.length,
}))

// We filter up to the active period (and active segemnt) - future periods
// should not be visible to the user
currentGame.periods = currentGame.periods.filter(
(period, ix) => ix <= currentGame.activePeriodIx
)
const activeSegmentIx = currentGame.activePeriod.activeSegmentIx

currentGame.activePeriod.segments = currentGame.activePeriod.segments.filter(
(segment, ix) => ix <= activeSegmentIx
)
currentGame.periods[currentGame.activePeriodIx].segments =
currentGame.periods[currentGame.activePeriodIx].segments.filter(
(segment, ix) => ix <= activeSegmentIx
)

const previousResults = ctx.prisma.playerResult.findMany({
where: {
playerId: args.playerId,
Expand Down
1 change: 1 addition & 0 deletions packages/platform/src/types/Game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const Period = objectType({
t.nonNull.field('facts', {
type: 'JSONObject',
})
t.int('segmentCount')
},
})

Expand Down
Loading

0 comments on commit c964a36

Please sign in to comment.