Skip to content

Commit

Permalink
Psych sheet current user highlight/info/scroll (thewca#10625)
Browse files Browse the repository at this point in the history
* Provide userInfo to RegistrationList

* Add user message & scroll to

* I18n

* Add Bootstrap CSS override for 'active' tr in SemUI

* Use Table.Row active prop

* Remove incorrect setter call

* Formatting

* Reorder message & simplify text

* lint errors

* lint warnings

* More lint

* Null safety for registration user id

* Switch prop to userId

* Only serialize id

* Directly pass user id to react

---------

Co-authored-by: Gregor Billing <[email protected]>
  • Loading branch information
kr-matthews and gregorbg authored Jan 26, 2025
1 parent 92de2b5 commit d0c2d93
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 69 deletions.
2 changes: 1 addition & 1 deletion app/views/registrations/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<% provide(:title, I18n.t('registrations.list.title', comp: @competition.name)) %>

<%= render layout: "nav" do %>
<%= react_component('RegistrationsV2/Registrations', { competitionInfo: @competition.to_competition_info }) %>
<%= react_component('RegistrationsV2/Registrations', { competitionInfo: @competition.to_competition_info, userId: @current_user&.id }) %>
<% end %>
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export default function CompetingStep({
[dispatch, eventsAreValid, hasChanges, maxEvents],
);

const actionCreateRegistration = () => {
const actionCreateRegistration = useCallback(() => {
createRegistrationMutation({
user_id: user.id,
competition_id: competitionInfo.id,
Expand All @@ -182,9 +182,16 @@ export default function CompetingStep({
},
guests,
});
};
}, [
createRegistrationMutation,
user.id,
competitionInfo.id,
selectedEvents,
comment,
guests,
]);

const actionUpdateRegistration = () => {
const actionUpdateRegistration = useCallback(() => {
confirm({
content: I18n.t(competitionInfo.allow_registration_edits ? 'competitions.registration_v2.update.update_confirm' : 'competitions.registration_v2.update.update_confirm_contact'),
}).then(() => {
Expand All @@ -206,9 +213,22 @@ export default function CompetingStep({
}).catch(() => {
nextStep();
});
};
}, [
confirm,
dispatch,
nextStep,
updateRegistrationMutation,
competitionInfo,
registration?.user_id,
hasCommentChanged,
comment,
hasEventsChanged,
selectedEvents,
hasGuestsChanged,
guests,
]);

const actionReRegister = () => {
const actionReRegister = useCallback(() => {
updateRegistrationMutation({
user_id: registration.user_id,
competition_id: competitionInfo.id,
Expand All @@ -219,7 +239,14 @@ export default function CompetingStep({
},
guests,
});
};
}, [
updateRegistrationMutation,
registration?.user_id,
competitionInfo.id,
comment,
selectedEvents,
guests,
]);

const handleEventSelection = ({ type, eventId }) => {
if (type === 'select_all_events') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { useQuery } from '@tanstack/react-query';
import React, {
useMemo,
useReducer,
useRef,
useState,
} from 'react';
import {
Flag, Icon, Segment, Table,
Button, Flag, Icon, Message, Segment, Table,
} from 'semantic-ui-react';
import _ from 'lodash';
import {
Expand All @@ -24,7 +25,7 @@ import { EventSelector } from '../../wca/EventSelector';

const sortReducer = createSortReducer(['name', 'country', 'total']);

export default function RegistrationList({ competitionInfo }) {
export default function RegistrationList({ competitionInfo, userId }) {
const { isLoading: registrationsLoading, data: registrations, isError } = useQuery({
queryKey: ['registrations', competitionInfo.id],
queryFn: () => getConfirmedRegistrations(competitionInfo),
Expand Down Expand Up @@ -68,7 +69,6 @@ export default function RegistrationList({ competitionInfo }) {

const registrationsWithPsychSheet = useMemo(() => {
if (psychSheet !== undefined) {
setPsychSheetSortBy(psychSheet.sort_by);
return psychSheet.sorted_rankings.map((p) => {
const registrationEntry = registrations.find((r) => p.user_id === r.user_id);
return { ...p, ...registrationEntry };
Expand Down Expand Up @@ -105,6 +105,11 @@ export default function RegistrationList({ competitionInfo }) {
return [];
}, [isAllCompetitors, registrationsWithPsychSheet, sortColumn, sortDirection]);

const userRegistration = data?.find((row) => row.user_id === userId);
const userIsInTable = Boolean(userRegistration);
const userPosition = userRegistration?.pos;
const userRowRef = useRef();

if (isError) {
return (
<Errored componentName="RegistrationList" />
Expand All @@ -131,6 +136,25 @@ export default function RegistrationList({ competitionInfo }) {
eventList={competitionInfo.event_ids}
selectedEvents={[psychSheetEvent].filter(Boolean)}
/>
{userIsInTable && (
<Message>
<Button
size="mini"
onClick={
() => userRowRef?.current?.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
>
{I18n.t('competitions.registration_v2.list.psychsheets.show_me')}
</Button>
{' '}
{(userPosition || isPsychSheet) && (
I18n.t(
'competitions.registration_v2.list.psychsheets.rank',
{ userPosition: userPosition ?? '-' },
)
)}
</Message>
)}
<Table striped sortable unstackable compact singleLine textAlign="left">
<Table.Header>
<Table.Row>
Expand Down Expand Up @@ -199,66 +223,74 @@ export default function RegistrationList({ competitionInfo }) {
</Table.Header>
<Table.Body>
{data.length > 0 ? (
data.map((registration) => (
<Table.Row key={`registration-table-row-${registration.user.id}`}>
{isPsychSheet && (
<Table.Cell
collapsing
textAlign="right"
disabled={registration.tied_previous}
>
{registration.pos}
</Table.Cell>
)}
<Table.Cell>
{registration.user.wca_id ? (
<a
href={personUrl(registration.user.wca_id)}
data.map((registration) => {
const isUser = registration.user_id === userId;
return (
<Table.Row
key={`registration-table-row-${registration.user.id}`}
active={isUser}
>
{isPsychSheet && (
<Table.Cell
collapsing
textAlign="right"
disabled={registration.tied_previous}
>
{registration.user.name}
</a>
) : (
registration.user.name
{registration.pos}
</Table.Cell>
)}
</Table.Cell>
<Table.Cell>
<Flag
name={registration.user.country.iso2.toLowerCase()}
/>
{countries.byIso2[registration.user.country.iso2].name}
</Table.Cell>
{isAllCompetitors ? (
<>
{competitionInfo.event_ids.map((id) => (
<Table.Cell
key={`registration-table-row-${registration.user.id}-${id}`}
>
{registration.competing.event_ids.includes(id) ? (
<EventIcon id={id} size="1em" hoverable={false} />
) : null}
<Table.Cell>
<div ref={isUser ? userRowRef : undefined}>
{registration.user.wca_id ? (
<a
href={personUrl(registration.user.wca_id)}
>
{registration.user.name}
</a>
) : (
registration.user.name
)}
</div>
</Table.Cell>
<Table.Cell>
<Flag
name={registration.user.country.iso2.toLowerCase()}
/>
{countries.byIso2[registration.user.country.iso2].name}
</Table.Cell>
{isAllCompetitors ? (
<>
{competitionInfo.event_ids.map((id) => (
<Table.Cell
key={`registration-table-row-${registration.user.id}-${id}`}
>
{registration.competing.event_ids.includes(id) ? (
<EventIcon id={id} size="1em" hoverable={false} />
) : null}
</Table.Cell>
))}
<Table.Cell>
{registration.competing.event_ids.length}
</Table.Cell>
))}
<Table.Cell>
{registration.competing.event_ids.length}
</Table.Cell>
</>
) : (
<>
<Table.Cell>
{psychSheetSortBy === 'single'
? registration.single_rank
: registration.average_rank}
</Table.Cell>
<Table.Cell>
{formatAttemptResult(registration.single_best, psychSheetEvent)}
</Table.Cell>
<Table.Cell>
{formatAttemptResult(registration.average_best, psychSheetEvent)}
</Table.Cell>
</>
)}
</Table.Row>
))
</>
) : (
<>
<Table.Cell>
{psychSheetSortBy === 'single'
? registration.single_rank
: registration.average_rank}
</Table.Cell>
<Table.Cell>
{formatAttemptResult(registration.single_best, psychSheetEvent)}
</Table.Cell>
<Table.Cell>
{formatAttemptResult(registration.average_best, psychSheetEvent)}
</Table.Cell>
</>
)}
</Table.Row>
);
})
) : (
<Table.Row>
<Table.Cell
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import RegistrationList from './RegistrationList';

export default function Index({ competitionInfo }) {
export default function Index({ competitionInfo, userId }) {
return (
<QueryClientProvider client={new QueryClient()}>
<RegistrationList
competitionInfo={competitionInfo}
userId={userId}
/>
</QueryClientProvider>
);
Expand Down
11 changes: 11 additions & 0 deletions app/webpacker/stylesheets/override.scss
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,15 @@ body, html {
.ui.radio.checkbox {
margin: 1.5px 0px;
}

// This overrides the Bootstrap table row color for the `active` property
// for the SemUI `active` property.
.ui.table > tbody > tr {
> td.active,
> th.active,
&.active > td,
&.active > th {
background-color: #e0e0e0 !important;
}
}
}
3 changes: 2 additions & 1 deletion config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1844,7 +1844,8 @@ en:
initialized: "Payment process was started on %{date}, but not finished."
refunded: "Payment was refunded on %{date}."
psychsheets:
go_back: "Go Back"
show_me: "Show me"
rank: "Rank: %{userPosition}"
timestamp: "Timestamp"
comment_and_note: "Comment & Note"
edit_waiting_list: "Enable Waiting List Edit Mode"
Expand Down

0 comments on commit d0c2d93

Please sign in to comment.