Skip to content

Commit

Permalink
Feat/improve match creation ux (#135)
Browse files Browse the repository at this point in the history
* style: fix broken match header

* fix: some refetching not working

* fix: match view not displaying data

* fix: empty match

* style: player match item

* debug: log failed requests in debug logs

* fix: misleading websocket state indicator

* fix: reconnect websocket on close

* fix: web socket status in debug logs

* style: fix groups button getting cut off

* fix: hide broken rules screen behind feature flag

* chore: modal to assign player points

* fix: overflowing player list not scrollable

* style: fix layout shift in match vs header

* feat: prevent new players with the same name as existing players from being created

* feat: add haptic feedback to input errors

* feat: success toast for creating a player

* chore: minor mobile app version bump

* style: display player initials on avatar while profile picture hasnt loaded

* chore: screen in case no finish move has been defined for a match

* feat: prevent creating two players with the same name during group creation

* fix: modal re-opening after dismissing (really bad fix that doesnt work for all cases)

* feat: functional flow for assigning finish move

* fix: scuffed dirty hacky fix for modal dismissal

* feat: enable new match creation flow

---------

Co-authored-by: LinusBolls <LinusBolls@users.noreply.github.com>
  • Loading branch information
LinusBolls and LinusBolls authored Nov 27, 2024
1 parent 8b4d3fa commit 42793f1
Show file tree
Hide file tree
Showing 23 changed files with 970 additions and 208 deletions.
40 changes: 20 additions & 20 deletions .github/workflows/api-staging-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,29 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- id: 'setup-qemu'
- id: "setup-qemu"
name: Set up QEMU
uses: docker/setup-qemu-action@v3
- id: 'docker-buildx-setup'
- id: "docker-buildx-setup"
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v2'
- id: "auth"
name: "Authenticate to Google Cloud"
uses: "google-github-actions/auth@v2"
with:
create_credentials_file: true
token_format: access_token
workload_identity_provider: 'projects/5685154754/locations/global/workloadIdentityPools/cd-beerpong/providers/github-actions'
service_account: 'cd-beerpong@beer-pong-441815.iam.gserviceaccount.com'
- id: 'login-gar'
workload_identity_provider: "projects/5685154754/locations/global/workloadIdentityPools/cd-beerpong/providers/github-actions"
service_account: "cd-beerpong@beer-pong-441815.iam.gserviceaccount.com"
- id: "login-gar"
name: "Login to GAR"
uses: docker/login-action@v3
with:
registry: europe-west10-docker.pkg.dev/beer-pong-441815/api-beerpong
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
- id: 'build-and-push'
name: 'Build and Push docker Image'
- id: "build-and-push"
name: "Build and Push docker Image"
uses: docker/build-push-action@v6
with:
push: true
Expand All @@ -66,21 +66,21 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v2'
- id: "auth"
name: "Authenticate to Google Cloud"
uses: "google-github-actions/auth@v2"
with:
create_credentials_file: true
token_format: access_token
workload_identity_provider: 'projects/5685154754/locations/global/workloadIdentityPools/cd-beerpong/providers/github-actions'
service_account: 'cd-beerpong@beer-pong-441815.iam.gserviceaccount.com'
- id: 'deploy'
uses: 'google-github-actions/deploy-cloudrun@v2'
workload_identity_provider: "projects/5685154754/locations/global/workloadIdentityPools/cd-beerpong/providers/github-actions"
service_account: "cd-beerpong@beer-pong-441815.iam.gserviceaccount.com"
- id: "deploy"
uses: "google-github-actions/deploy-cloudrun@v2"
with:
service: 'api-springboot-staging'
image: 'europe-west10-docker.pkg.dev/beer-pong-441815/api-beerpong/api-staging:${{ github.sha }}'
service: "api-springboot-staging"
image: "europe-west10-docker.pkg.dev/beer-pong-441815/api-beerpong/api-staging:${{ github.sha }}"
region: europe-west10
flags: '--port=8080 --add-cloudsql-instances=beer-pong-441815:europe-west10:beerpong-staging-db --no-cpu-throttling --min-instances 0 --max-instances 1 --allow-unauthenticated'
flags: "--port=8080 --add-cloudsql-instances=beer-pong-441815:europe-west10:beerpong-staging-db --no-cpu-throttling --min-instances 0 --max-instances 1 --allow-unauthenticated"
env_vars: |
POSTGRES_USER=postgres
POSTGRES_URL=jdbc:postgresql:///beerpong?cloudSqlInstance=beer-pong-441815:europe-west10:beerpong-staging-db&socketFactory=com.google.cloud.sql.postgres.SocketFactory
Expand Down
2 changes: 1 addition & 1 deletion mobile-app/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"expo": {
"name": "beerpong-tournament",
"slug": "mobile-app",
"version": "1.0.7",
"version": "1.0.8",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "myapp",
Expand Down
27 changes: 17 additions & 10 deletions mobile-app/app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';

import { useGroupQuery } from '@/api/calls/groupHooks';
import { env } from '@/api/env';
import { navStyles } from '@/app/navigation/navStyles';
import { useNavigation } from '@/app/navigation/useNavigation';
import { Colors } from '@/constants/Colors';
Expand Down Expand Up @@ -86,16 +87,22 @@ export default function TabLayout() {
...groupHeader,
}}
/>
<Tabs.Screen
name="rules"
options={{
title: 'Rules',
tabBarIcon: ({ color }) => (
<Icon color={color} size={32} name="format-section" />
),
...groupHeader,
}}
/>
{env.isDev && (
<Tabs.Screen
name="rules"
options={{
title: 'Rules',
tabBarIcon: ({ color }) => (
<Icon
color={color}
size={32}
name="format-section"
/>
),
...groupHeader,
}}
/>
)}
<Tabs.Screen
name="settings"
options={{
Expand Down
21 changes: 18 additions & 3 deletions mobile-app/app/createNewPlayer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useCreatePlayerMutation } from '@/api/calls/playerHooks';
import {
useCreatePlayerMutation,
usePlayersQuery,
} from '@/api/calls/playerHooks';
import { useGroup } from '@/api/calls/seasonHooks';
import CreateNewPlayer from '@/components/screens/CreateNewPlayer';
import { showErrorToast } from '@/toast';
import { showErrorToast, showSuccessToast } from '@/toast';
import { ConsoleLogger } from '@/utils/logging';

import { useNavigation } from './navigation/useNavigation';
Expand All @@ -11,6 +14,12 @@ export default function Page() {

const { groupId, seasonId } = useGroup();

const playersQuery = usePlayersQuery(groupId, seasonId);

const players = playersQuery.data?.data ?? [];

const existingPlayers = players.map((i) => i.profile!.name!);

const { mutateAsync } = useCreatePlayerMutation();

async function onSubmit(player: { name: string }) {
Expand All @@ -22,12 +31,18 @@ export default function Page() {
seasonId,
name: player.name,
});
showSuccessToast(`Created player "${player.name}".`);
nav.goBack();
} catch (err) {
ConsoleLogger.error('failed to create player:', err);
showErrorToast('Failed to create player.');
}
}

return <CreateNewPlayer onCreate={onSubmit} />;
return (
<CreateNewPlayer
onCreate={onSubmit}
existingPlayers={existingPlayers}
/>
);
}
8 changes: 5 additions & 3 deletions mobile-app/app/debugLog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import React, { useEffect, useState } from 'react';
import { ScrollView } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';

import { env } from '@/api/env';
import { useApi } from '@/api/utils/create-api';
import { navStyles } from '@/app/navigation/navStyles';
import { Heading } from '@/components/Menu/MenuSection';
Expand Down Expand Up @@ -63,11 +62,14 @@ export default function Page() {
<Heading
title={
<>
Debug Logs{' '}
{env.isDev ? (isRealtimeOpen ? '✅' : '❌') : ''}
Web Socket{' '}
{isRealtimeOpen
? 'connected ✅'
: 'disconnected ❌'}
</>
}
/>
<Heading title="Debug Logs" />
{logs.map((i, idx) => (
<Text color="primary" key={idx} style={{ fontSize: 12 }}>
<Text color="secondary" style={{ fontSize: 12 }}>
Expand Down
94 changes: 87 additions & 7 deletions mobile-app/app/newMatchPoints.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React from 'react';
import React, { useState } from 'react';

import { useCreateMatchMutation } from '@/api/calls/matchHooks';
import { usePlayersQuery } from '@/api/calls/playerHooks';
import { useMoves } from '@/api/calls/ruleHooks';
import { useGroup } from '@/api/calls/seasonHooks';
import { TeamMember } from '@/api/utils/matchDtoToMatch';
import { useNavigation } from '@/app/navigation/useNavigation';
import AssignFinishModeModal from '@/components/AssignFinishMoveModal';
import AssignPointsToPlayerModal from '@/components/AssignPointsToPlayerModal';
import CreateMatchAssignPoints from '@/components/screens/CreateMatchAssignPoints';
import { Feature } from '@/constants/Features';
import { showErrorToast } from '@/toast';
import { ConsoleLogger } from '@/utils/logging';
import { useMatchDraftStore } from '@/zustand/matchDraftStore';
Expand All @@ -16,6 +19,10 @@ export default function Page() {

const matchDraft = useMatchDraftStore();

const [playerIdx, setPlayerIdx] = useState<number | null>(0);

const [showFinishMoveModal, setShowFinishMoveModal] = useState(false);

const { mutateAsync } = useCreateMatchMutation();

const { groupId, seasonId } = useGroup();
Expand Down Expand Up @@ -44,7 +51,14 @@ export default function Page() {
team: i.team,
avatarUrl: profile.profile.avatarAsset?.url,
name: profile.profile.name || 'Unknown',
points: 1,
points: i.moves.reduce(
(sum, j) =>
sum +
j.count *
(allowedMoves.find((k) => k.id === j.moveId)
?.pointsForScorer ?? 0),
0
),
change: 0.12,
moves: allowedMoves.map((j) => {
return {
Expand All @@ -59,9 +73,23 @@ export default function Page() {
};
});

const finishes = teamMembers
.flatMap((i) => i.moves)
.filter((i) => i.isFinish);

const numFinishes = finishes.reduce((sum, i) => sum + i.count, 0);

const isValidGame = numFinishes === 1;

async function onSubmit() {
if (!groupId || !seasonId) return;

if (Feature.POINTS_ASSIGNMENT_MODAL.isEnabled && !isValidGame) {
setShowFinishMoveModal(true);

return;
}

try {
await mutateAsync({
groupId,
Expand All @@ -77,10 +105,62 @@ export default function Page() {
}

return (
<CreateMatchAssignPoints
players={teamMembers}
setMoveCount={matchDraft.actions.setMoveCount}
onSubmit={onSubmit}
/>
<>
{Feature.POINTS_ASSIGNMENT_MODAL.isEnabled && (
<AssignPointsToPlayerModal
onClose={() => setPlayerIdx(null)}
playerIdx={playerIdx}
setPlayerIdx={setPlayerIdx}
match={{
blueCups: players
.filter((i) => i.team === 'blue')
.map((i) => i.moves)
.flat()
.reduce((sum, i) => sum + i.count, 0),
redCups: players
.filter((i) => i.team === 'red')
.map((i) => i.moves)
.flat()
.reduce((sum, i) => sum + i.count, 0),
redTeam: teamMembers.filter((i) => i.team === 'red'),
blueTeam: teamMembers.filter((i) => i.team === 'blue'),
}}
editable
isVisible={playerIdx != null}
setMoveCount={matchDraft.actions.setMoveCount}
/>
)}
<AssignFinishModeModal
onSubmit={(playerId, moveId) =>
matchDraft.actions.setMoveCount(playerId, moveId, 1)
}
onClose={() => setShowFinishMoveModal(false)}
isVisible={showFinishMoveModal}
match={{
blueCups: players
.filter((i) => i.team === 'blue')
.map((i) => i.moves)
.flat()
.reduce((sum, i) => sum + i.count, 0),
redCups: players
.filter((i) => i.team === 'red')
.map((i) => i.moves)
.flat()
.reduce((sum, i) => sum + i.count, 0),
redTeam: teamMembers.filter((i) => i.team === 'red'),
blueTeam: teamMembers.filter((i) => i.team === 'blue'),
}}
/>
<CreateMatchAssignPoints
players={teamMembers}
setMoveCount={matchDraft.actions.setMoveCount}
onSubmit={onSubmit}
onPlayerPress={(player) =>
setPlayerIdx(
teamMembers.findIndex((i) => i.id === player.id)
)
}
/>
</>
);
}
Loading

0 comments on commit 42793f1

Please sign in to comment.