Skip to content

Commit

Permalink
Add newer components
Browse files Browse the repository at this point in the history
  • Loading branch information
simonkellly committed Jun 21, 2024
1 parent 714cb80 commit b19dea6
Show file tree
Hide file tree
Showing 6 changed files with 452 additions and 2 deletions.
47 changes: 45 additions & 2 deletions app/views/persons/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,49 @@
<% if @enable_react %>
<% provide(:title, @person.name) %>
<%= react_component("Persons/NewPerson", {
person: {
name: @person.name,
user: @person.user,
previousPersons: @previous_persons.map { |person| {
name: person.name,
country: person.country.name,
}},
wcaId: @person.wca_id,
gender: @person.gender_visible? ? @person.gender : nil,
country: {
name: @person.country.name,
iso2: @person.country_iso2,
},
competitionCount: @person.competitions.count,
completedSolves: @person.completed_solves_count,
medals: @medals,
records: @records,
averageRanks: @ranks_average.map { |r| {
eventId: r.eventId,
time: r.solve_time.clock_format,
worldRank: r.worldRank,
continentRank: r.continentRank,
countryRank: r.countryRank,
oddRank: odd_rank?(r),
rankPath: rankings_path(r.event_id, "average")
}},
singleRanks: @ranks_single.map { |r| {
eventId: r.eventId,
time: r.solve_time.clock_format,
worldRank: r.worldRank,
continentRank: r.continentRank,
countryRank: r.countryRank,
oddRank: odd_rank?(r),
rankPath: rankings_path(r.event_id, "single"),
data: r.inspect
}},
results: [],
},
}) %>
<% else %>
<% provide(:title, @person.name) %>
<%= react_component("Persons/Person", {
normalPerson: @person,
person: {
Expand Down Expand Up @@ -34,7 +77,8 @@
continentRank: r.continentRank,
countryRank: r.countryRank,
oddRank: odd_rank?(r),
rankPath: rankings_path(r.event_id, "single")
rankPath: rankings_path(r.event_id, "single"),
data: r.inspect
}},
medals: @medals,
records: @records,
Expand Down Expand Up @@ -66,6 +110,5 @@
canEditUser: current_user&.can_edit_user?(@person.user),
editUrl: edit_user_path(@person.user),
}) %>
<% else %>
<%= render "show_legacy"%>
<% end %>
78 changes: 78 additions & 0 deletions app/webpacker/components/Persons/NewPerson/CountStats.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
Card, CardContent, Icon, Table,
} from 'semantic-ui-react';
import React from 'react';

function CountStat({ title, data, color }) {
return (
<Card fluid className="small-card" color={color}>
<Card.Content>
<Card.Header textAlign="center">
{title}
</Card.Header>
<Card.Description>
<Table basic="very" className="count-stat" unstackable>
<Table.Body>
{data.map((d) => (
<Table.Row key={d.label}>
<Table.Cell>
<Icon name={d.icon} color={d.iconColor} />
&nbsp;
{d.label}
</Table.Cell>
<Table.Cell textAlign="center">{d.count}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
</Card.Description>
</Card.Content>
<CardContent extra>
Total:
{' '}
{data.reduce((acc, d) => acc + d.count, 0)}
</CardContent>
</Card>
);
}

export default function CountStats({ person }) {
return (
<>
{person.medals.total > 0 && (
<CountStat
title="Medals"
color="yellow"
data={[
{
label: 'Gold', icon: 'trophy', iconColor: 'yellow', count: person.medals.gold,
},
{
label: 'Silver', icon: 'trophy', iconColor: 'grey', count: person.medals.silver,
},
{
label: 'Bronze', icon: 'trophy', iconColor: 'orange', count: person.medals.bronze,
},
]}
/>
)}
{person.records.total > 0 && (
<CountStat
title="Records"
color="red"
data={[
{
label: 'WR', icon: 'globe', iconColor: 'green', count: person.records.world,
},
{
label: 'CR', icon: 'map', iconColor: 'teal', count: person.records.continental,
},
{
label: 'NR', icon: 'flag', iconColor: 'blue', count: person.records.national,
},
]}
/>
)}
</>
);
}
69 changes: 69 additions & 0 deletions app/webpacker/components/Persons/NewPerson/ProfileDetails.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';
import { Card, Grid, Header } from 'semantic-ui-react';
import i18n from "../../../lib/i18n";

function Stat({ children, label, width }) {
return (
<Grid.Column
stretched
className="stat"
width={width}
>
<Header size="tiny" sub block>
{label}
<Header className="stat">{children}</Header>
</Header>
</Grid.Column>
);
}

function FlagIcon({ countryIso2 }) {
return (
<span
className={`fi fi-${countryIso2.toLowerCase()}`}
/>
);
}

export default function ProfileDetails({ person }) {
const profile = {
region: person.country,
wcaId: person.wcaId,
gender: person.gender,
competitions: person.competitionCount,
solves: person.completedSolves,
};
const statCount = 2
+ (profile.gender ? 1 : 0)
+ (profile.competitions ? 1 : 0)
+ (profile.solves ? 1 : 0);

const regionWidth = 16; // (statCount % 2) == 1 ? 11 : 8;
const idWidth = (statCount % 2) === 0 ? 16 : 8;
const otherWidth = 8;

return (
<Card fluid className="large-card" color="blue">
<Card.Content>
<Card.Header textAlign="center">
Profile
</Card.Header>
<Grid textAlign="center" className="stat-grid">
<Stat label="Region" width={regionWidth}>
<FlagIcon countryIso2={profile.region.iso2} />
{' '}
{profile.region.name}
</Stat>
<Stat label="WCA ID" width={idWidth}>{profile.wcaId}</Stat>
{profile.gender && (
<Stat label="Gender" width={otherWidth}>
{i18n.t(`enums.user.gender.${profile.gender}`)}
</Stat>
)}
{profile.solves && <Stat label="Solves" width={otherWidth}>{profile.solves}</Stat>}
{profile.competitions && <Stat label="Competitions" width={otherWidth}>{profile.competitions}</Stat>}
</Grid>
</Card.Content>
</Card>
);
}
111 changes: 111 additions & 0 deletions app/webpacker/components/Persons/NewPerson/RecordTable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React from 'react';
import { Icon, Popup, Table } from 'semantic-ui-react';
import I18nHTMLTranslate from '../../I18nHTMLTranslate';
import { events } from '../../../lib/wca-data.js.erb';
import I18n from '../../../lib/i18n';
import EventIcon from '../../wca/EventIcon';

function RankCell({ ranks, type }) {
if (!ranks) return <Table.Cell />;

const rank = ranks[`${type}Rank`];
if (rank === undefined) return <Table.Cell />;

const opacity = rank === 1 ? 1 : {
country: 0.6,
continent: 0.8,
world: 1,
}[type];

const color = rank === 1 ? 'red' : undefined;

return (
<Table.Cell>
<span
style={{
opacity,
color,
}}
>
{rank === 0 ? '-' : rank}
</span>
</Table.Cell>
);
}

function EventData({ event, person, anyOdd }) {
const singles = person.singleRanks;
const averages = person.averageRanks;

const singleForEvent = singles.find((r) => r.eventId === event);
const averageForEvent = averages.find((r) => r.eventId === event);
if (!singleForEvent && !averageForEvent) return null;

const isOdd = singleForEvent.oddRank || averageForEvent?.oddRank;

return (
<Table.Row textAlign="right">
<Table.Cell textAlign="left">
<EventIcon id={event} />
{' '}
<I18nHTMLTranslate i18nKey={`events.${event}`} />
</Table.Cell>
<RankCell ranks={singleForEvent} type="country" />
<RankCell ranks={singleForEvent} type="continent" />
<RankCell ranks={singleForEvent} type="world" />
<Table.Cell><b>{singleForEvent?.time}</b></Table.Cell>
<Table.Cell><b>{averageForEvent?.time}</b></Table.Cell>
<RankCell ranks={averageForEvent} type="world" />
<RankCell ranks={averageForEvent} type="continent" />
<RankCell ranks={averageForEvent} type="country" />
{anyOdd && (
<Table.Cell>
{isOdd && (
<Popup
content={I18n.t('persons.show.odd_rank_reason')}
trigger={(
<Icon
name="question circle"
/>
)}
/>
)}
</Table.Cell>
)}
</Table.Row>
);
}

export default function RecordTable({ person }) {
const { singleRanks, averageRanks } = person;
const anyOddRank = singleRanks.some((r) => r.oddRank) || averageRanks.some((r) => r.oddRank);

return (
<Table unstackable compact="very" singleLine basic="very" striped>
<Table.Header>
<Table.Row textAlign="right">
<Table.HeaderCell textAlign="left">Event</Table.HeaderCell>
<Table.HeaderCell>NR</Table.HeaderCell>
<Table.HeaderCell>CR</Table.HeaderCell>
<Table.HeaderCell>WR</Table.HeaderCell>
<Table.HeaderCell>Single</Table.HeaderCell>
<Table.HeaderCell>Average</Table.HeaderCell>
<Table.HeaderCell>WR</Table.HeaderCell>
<Table.HeaderCell>CR</Table.HeaderCell>
<Table.HeaderCell>NR</Table.HeaderCell>
{anyOddRank && <Table.HeaderCell />}
</Table.Row>
</Table.Header>
<Table.Body>
{events.official.map((event) => (
<EventData
key={event.id}
event={event.id}
person={person}
anyOdd={anyOddRank}
/>
))}
</Table.Body>
</Table>
);
}
Loading

0 comments on commit b19dea6

Please sign in to comment.