v3 release #75

Merged
alekswilc merged 63 commits from v3 into main 2024-12-13 20:29:17 +01:00
14 changed files with 278 additions and 235 deletions
Showing only changes of commit 2ad1e61c6a - Show all commits

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

7
.idea/discord.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
<option name="description" value="" />
</component>
</project>

6
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="openjdk-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/simrail.alekswilc.dev.iml" filepath="$PROJECT_DIR$/.idea/simrail.alekswilc.dev.iml" />
</modules>
</component>
</project>

9
.idea/simrail.alekswilc.dev.iml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,57 @@
import { assert } from 'node:console';
export interface IResponse<T> {
success: boolean
data: T;
code: number
}
export class BaseResponseBuilder<T> {
protected success: IResponse<T>['success'] = undefined!;
protected data: IResponse<T>['data'] = undefined!;
protected code: IResponse<T>['code'] = undefined!;
public constructor(data?: Partial<IResponse<T>>) {
if (!data) return;
if ('success' in data) this.success = data.success as IResponse<T>['success'];
if ('data' in data) this.data = data.data as IResponse<T>['data'];
if ('code' in data) this.code = data.code as IResponse<T>['code'];
}
public setData(data: T) {
this.data = data;
return this;
}
public setCode(code: number) {
this.code = code;
return this;
}
public toJSON() {
const { success, data, code } = this;
assert(typeof(success) === 'boolean', 'expected success to be boolean');
assert(typeof(code) === 'number', 'expected success to be number');
return {
success, data, code
}
}
}
export class SuccessResponseBuilder<T> extends BaseResponseBuilder<T> {
public constructor(options?: IResponse<T>) {
super(options);
this.success = true;
}
}
export class ErrorResponseBuilder<T> extends BaseResponseBuilder<T> {
public constructor(options?: IResponse<T>) {
super(options);
this.success = false;
}
}

View File

@ -3,8 +3,10 @@ import dayjs from 'dayjs';
import { msToTime } from '../../util/time.js';
import { PipelineStage } from 'mongoose';
import { MProfile, raw_schema } from '../../mongo/profile.js';
import { IProfile, MProfile, raw_schema } from '../../mongo/profile.js';
import { GitUtil } from '../../util/git.js';
import { SuccessResponseBuilder } from '../responseBuilder.js';
import { removeProperties } from '../../util/functions.js';
const generateSearch = (regex: RegExp) => [
{
@ -39,15 +41,12 @@ export class LeaderboardRoute {
.limit(10)
res.render('leaderboard/index.ejs', {
records,
dayjs,
msToTime,
type: 'train',
q: req.query.q,
...GitUtil.getData(),
});
res.json(
new SuccessResponseBuilder<{ records: Omit<IProfile, '_id' | '__v'>[] }>()
.setCode(200)
.setData({ records: records.map(x => removeProperties<Omit<IProfile, '_id' | '__v'>>(x, ['_id', '__v'])) })
.toJSON()
);
})

View File

@ -0,0 +1,8 @@
// TODO: typings
export const removeProperties = <T>(data: any, names: string[]) => {
for (const name of names)
delete data[name];
return data as T;
}

View File

@ -12,6 +12,7 @@ import Alerts from './pages/UiElements/Alerts';
import Buttons from './pages/UiElements/Buttons';
import DefaultLayout from './layout/DefaultLayout';
import "./i18n";
import { TrainLogs } from './pages/Logs.tsx';
function App() {
@ -41,11 +42,11 @@ function App() {
}
/>
<Route
path="/profile"
path="/logs/trains"
element={
<>
<PageTitle title="Profile | TailAdmin - Tailwind CSS Admin Dashboard Template" />
<Profile />
<PageTitle title="simrail.alekswilc.dev | Train Logs" />
<TrainLogs />
</>
}
/>

View File

@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from 'react';
import { NavLink, useLocation } from 'react-router-dom';
import SidebarLinkGroup from './SidebarLinkGroup';
import Logo from '../../images/logo/logo.svg';
import { useTranslation } from 'react-i18next';
interface SidebarProps {
sidebarOpen: boolean;
@ -11,7 +12,7 @@ interface SidebarProps {
const Sidebar = ({ sidebarOpen, setSidebarOpen }: SidebarProps) => {
const location = useLocation();
const { pathname } = location;
const trigger = useRef<any>(null);
const sidebar = useRef<any>(null);
@ -20,6 +21,8 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen }: SidebarProps) => {
storedSidebarExpanded === null ? false : storedSidebarExpanded === 'true'
);
const { t } = useTranslation();
// close on click outside
useEffect(() => {
const clickHandler = ({ target }: MouseEvent) => {
@ -93,166 +96,25 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen }: SidebarProps) => {
<nav className="mt-5 py-4 px-4 lg:mt-9 lg:px-6">
{/* <!-- Menu Group --> */}
<div>
<h3 className="mb-4 ml-4 text-sm font-semibold text-bodydark2">
MENU
</h3>
<ul className="mb-6 flex flex-col gap-1.5">
{/* <!-- Menu Item Dashboard --> */}
<SidebarLinkGroup
activeCondition={
pathname === '/' || pathname.includes('dashboard')
}
>
{(handleClick, open) => {
return (
<React.Fragment>
<NavLink
to="#"
className={`group relative flex items-center gap-2.5 rounded-sm px-4 py-2 font-medium text-bodydark1 duration-300 ease-in-out hover:bg-graydark dark:hover:bg-meta-4 ${
(pathname === '/' ||
pathname.includes('dashboard')) &&
'bg-graydark dark:bg-meta-4'
}`}
onClick={(e) => {
e.preventDefault();
sidebarExpanded
? handleClick()
: setSidebarExpanded(true);
}}
>
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.10322 0.956299H2.53135C1.5751 0.956299 0.787598 1.7438 0.787598 2.70005V6.27192C0.787598 7.22817 1.5751 8.01567 2.53135 8.01567H6.10322C7.05947 8.01567 7.84697 7.22817 7.84697 6.27192V2.72817C7.8751 1.7438 7.0876 0.956299 6.10322 0.956299ZM6.60947 6.30005C6.60947 6.5813 6.38447 6.8063 6.10322 6.8063H2.53135C2.2501 6.8063 2.0251 6.5813 2.0251 6.30005V2.72817C2.0251 2.44692 2.2501 2.22192 2.53135 2.22192H6.10322C6.38447 2.22192 6.60947 2.44692 6.60947 2.72817V6.30005Z"
fill=""
/>
<path
d="M15.4689 0.956299H11.8971C10.9408 0.956299 10.1533 1.7438 10.1533 2.70005V6.27192C10.1533 7.22817 10.9408 8.01567 11.8971 8.01567H15.4689C16.4252 8.01567 17.2127 7.22817 17.2127 6.27192V2.72817C17.2127 1.7438 16.4252 0.956299 15.4689 0.956299ZM15.9752 6.30005C15.9752 6.5813 15.7502 6.8063 15.4689 6.8063H11.8971C11.6158 6.8063 11.3908 6.5813 11.3908 6.30005V2.72817C11.3908 2.44692 11.6158 2.22192 11.8971 2.22192H15.4689C15.7502 2.22192 15.9752 2.44692 15.9752 2.72817V6.30005Z"
fill=""
/>
<path
d="M6.10322 9.92822H2.53135C1.5751 9.92822 0.787598 10.7157 0.787598 11.672V15.2438C0.787598 16.2001 1.5751 16.9876 2.53135 16.9876H6.10322C7.05947 16.9876 7.84697 16.2001 7.84697 15.2438V11.7001C7.8751 10.7157 7.0876 9.92822 6.10322 9.92822ZM6.60947 15.272C6.60947 15.5532 6.38447 15.7782 6.10322 15.7782H2.53135C2.2501 15.7782 2.0251 15.5532 2.0251 15.272V11.7001C2.0251 11.4188 2.2501 11.1938 2.53135 11.1938H6.10322C6.38447 11.1938 6.60947 11.4188 6.60947 11.7001V15.272Z"
fill=""
/>
<path
d="M15.4689 9.92822H11.8971C10.9408 9.92822 10.1533 10.7157 10.1533 11.672V15.2438C10.1533 16.2001 10.9408 16.9876 11.8971 16.9876H15.4689C16.4252 16.9876 17.2127 16.2001 17.2127 15.2438V11.7001C17.2127 10.7157 16.4252 9.92822 15.4689 9.92822ZM15.9752 15.272C15.9752 15.5532 15.7502 15.7782 15.4689 15.7782H11.8971C11.6158 15.7782 11.3908 15.5532 11.3908 15.272V11.7001C11.3908 11.4188 11.6158 11.1938 11.8971 11.1938H15.4689C15.7502 11.1938 15.9752 11.4188 15.9752 11.7001V15.272Z"
fill=""
/>
</svg>
Dashboard
<svg
className={`absolute right-4 top-1/2 -translate-y-1/2 fill-current ${
open && 'rotate-180'
}`}
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.41107 6.9107C4.73651 6.58527 5.26414 6.58527 5.58958 6.9107L10.0003 11.3214L14.4111 6.91071C14.7365 6.58527 15.2641 6.58527 15.5896 6.91071C15.915 7.23614 15.915 7.76378 15.5896 8.08922L10.5896 13.0892C10.2641 13.4147 9.73651 13.4147 9.41107 13.0892L4.41107 8.08922C4.08563 7.76378 4.08563 7.23614 4.41107 6.9107Z"
fill=""
/>
</svg>
</NavLink>
{/* <!-- Dropdown Menu Start --> */}
<div
className={`translate transform overflow-hidden ${
!open && 'hidden'
}`}
>
<ul className="mt-4 mb-5.5 flex flex-col gap-2.5 pl-6">
<li>
<NavLink
to="/"
className={({ isActive }) =>
'group relative flex items-center gap-2.5 rounded-md px-4 font-medium text-bodydark2 duration-300 ease-in-out hover:text-white ' +
(isActive && '!text-white')
}
>
eCommerce
</NavLink>
</li>
</ul>
</div>
{/* <!-- Dropdown Menu End --> */}
</React.Fragment>
);
}}
</SidebarLinkGroup>
{/* <!-- Menu Item Dashboard --> */}
{/* <!-- Menu Item Calendar --> */}
<li>
<NavLink
to="/calendar"
to="/"
className={`group relative flex items-center gap-2.5 rounded-sm py-2 px-4 font-medium text-bodydark1 duration-300 ease-in-out hover:bg-graydark dark:hover:bg-meta-4 ${
pathname.includes('calendar') &&
pathname === '/' &&
'bg-graydark dark:bg-meta-4'
}`}
>
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M15.7499 2.9812H14.2874V2.36245C14.2874 2.02495 14.0062 1.71558 13.6405 1.71558C13.2749 1.71558 12.9937 1.99683 12.9937 2.36245V2.9812H4.97803V2.36245C4.97803 2.02495 4.69678 1.71558 4.33115 1.71558C3.96553 1.71558 3.68428 1.99683 3.68428 2.36245V2.9812H2.2499C1.29365 2.9812 0.478027 3.7687 0.478027 4.75308V14.5406C0.478027 15.4968 1.26553 16.3125 2.2499 16.3125H15.7499C16.7062 16.3125 17.5218 15.525 17.5218 14.5406V4.72495C17.5218 3.7687 16.7062 2.9812 15.7499 2.9812ZM1.77178 8.21245H4.1624V10.9968H1.77178V8.21245ZM5.42803 8.21245H8.38115V10.9968H5.42803V8.21245ZM8.38115 12.2625V15.0187H5.42803V12.2625H8.38115ZM9.64678 12.2625H12.5999V15.0187H9.64678V12.2625ZM9.64678 10.9968V8.21245H12.5999V10.9968H9.64678ZM13.8374 8.21245H16.228V10.9968H13.8374V8.21245ZM2.2499 4.24683H3.7124V4.83745C3.7124 5.17495 3.99365 5.48433 4.35928 5.48433C4.7249 5.48433 5.00615 5.20308 5.00615 4.83745V4.24683H13.0499V4.83745C13.0499 5.17495 13.3312 5.48433 13.6968 5.48433C14.0624 5.48433 14.3437 5.20308 14.3437 4.83745V4.24683H15.7499C16.0312 4.24683 16.2562 4.47183 16.2562 4.75308V6.94683H1.77178V4.75308C1.77178 4.47183 1.96865 4.24683 2.2499 4.24683ZM1.77178 14.5125V12.2343H4.1624V14.9906H2.2499C1.96865 15.0187 1.77178 14.7937 1.77178 14.5125ZM15.7499 15.0187H13.8374V12.2625H16.228V14.5406C16.2562 14.7937 16.0312 15.0187 15.7499 15.0187Z"
fill=""
/>
</svg>
Calendar
{t('pages.home')}
</NavLink>
</li>
{/* <!-- Menu Item Calendar --> */}
{/* <!-- Menu Item Profile --> */}
<li>
<NavLink
to="/profile"
className={`group relative flex items-center gap-2.5 rounded-sm py-2 px-4 font-medium text-bodydark1 duration-300 ease-in-out hover:bg-graydark dark:hover:bg-meta-4 ${
pathname.includes('profile') && 'bg-graydark dark:bg-meta-4'
}`}
>
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.0002 7.79065C11.0814 7.79065 12.7689 6.1594 12.7689 4.1344C12.7689 2.1094 11.0814 0.478149 9.0002 0.478149C6.91895 0.478149 5.23145 2.1094 5.23145 4.1344C5.23145 6.1594 6.91895 7.79065 9.0002 7.79065ZM9.0002 1.7719C10.3783 1.7719 11.5033 2.84065 11.5033 4.16252C11.5033 5.4844 10.3783 6.55315 9.0002 6.55315C7.62207 6.55315 6.49707 5.4844 6.49707 4.16252C6.49707 2.84065 7.62207 1.7719 9.0002 1.7719Z"
fill=""
/>
<path
d="M10.8283 9.05627H7.17207C4.16269 9.05627 1.71582 11.5313 1.71582 14.5406V16.875C1.71582 17.2125 1.99707 17.5219 2.3627 17.5219C2.72832 17.5219 3.00957 17.2407 3.00957 16.875V14.5406C3.00957 12.2344 4.89394 10.3219 7.22832 10.3219H10.8564C13.1627 10.3219 15.0752 12.2063 15.0752 14.5406V16.875C15.0752 17.2125 15.3564 17.5219 15.7221 17.5219C16.0877 17.5219 16.3689 17.2407 16.3689 16.875V14.5406C16.2846 11.5313 13.8377 9.05627 10.8283 9.05627Z"
fill=""
/>
</svg>
Profile
</NavLink>
</li>
{/* <!-- Menu Item Profile --> */}
{/* <!-- Menu Item Forms --> */}
<SidebarLinkGroup
activeCondition={
pathname === '/forms' || pathname.includes('forms')
pathname === '/logs' || pathname.includes('logs')
}
>
{(handleClick, open) => {
@ -261,8 +123,8 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen }: SidebarProps) => {
<NavLink
to="#"
className={`group relative flex items-center gap-2.5 rounded-sm py-2 px-4 font-medium text-bodydark1 duration-300 ease-in-out hover:bg-graydark dark:hover:bg-meta-4 ${
(pathname === '/forms' ||
pathname.includes('forms')) &&
(pathname === '/logs' ||
pathname.includes('logs')) &&
'bg-graydark dark:bg-meta-4'
}`}
onClick={(e) => {
@ -272,36 +134,8 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen }: SidebarProps) => {
: setSidebarExpanded(true);
}}
>
<svg
className="fill-current"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.43425 7.5093H2.278C2.44675 7.5093 2.55925 7.3968 2.58737 7.31243L2.98112 6.32805H5.90612L6.27175 7.31243C6.328 7.48118 6.46862 7.5093 6.58112 7.5093H7.453C7.76237 7.48118 7.87487 7.25618 7.76237 7.03118L5.428 1.4343C5.37175 1.26555 5.3155 1.23743 5.14675 1.23743H3.88112C3.76862 1.23743 3.59987 1.29368 3.57175 1.4343L1.153 7.08743C1.0405 7.2843 1.20925 7.5093 1.43425 7.5093ZM4.47175 2.98118L5.3155 5.17493H3.59987L4.47175 2.98118Z"
fill=""
/>
<path
d="M10.1249 2.5031H16.8749C17.2124 2.5031 17.5218 2.22185 17.5218 1.85623C17.5218 1.4906 17.2405 1.20935 16.8749 1.20935H10.1249C9.7874 1.20935 9.47803 1.4906 9.47803 1.85623C9.47803 2.22185 9.75928 2.5031 10.1249 2.5031Z"
fill=""
/>
<path
d="M16.8749 6.21558H10.1249C9.7874 6.21558 9.47803 6.49683 9.47803 6.86245C9.47803 7.22808 9.75928 7.50933 10.1249 7.50933H16.8749C17.2124 7.50933 17.5218 7.22808 17.5218 6.86245C17.5218 6.49683 17.2124 6.21558 16.8749 6.21558Z"
fill=""
/>
<path
d="M16.875 11.1656H1.77187C1.43438 11.1656 1.125 11.4469 1.125 11.8125C1.125 12.1781 1.40625 12.4594 1.77187 12.4594H16.875C17.2125 12.4594 17.5219 12.1781 17.5219 11.8125C17.5219 11.4469 17.2125 11.1656 16.875 11.1656Z"
fill=""
/>
<path
d="M16.875 16.1156H1.77187C1.43438 16.1156 1.125 16.3969 1.125 16.7625C1.125 17.1281 1.40625 17.4094 1.77187 17.4094H16.875C17.2125 17.4094 17.5219 17.1281 17.5219 16.7625C17.5219 16.3969 17.2125 16.1156 16.875 16.1156Z"
fill="white"
/>
</svg>
Forms
{t('pages.logs')}
<svg
className={`absolute right-4 top-1/2 -translate-y-1/2 fill-current ${
open && 'rotate-180'
@ -329,24 +163,24 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen }: SidebarProps) => {
<ul className="mt-4 mb-5.5 flex flex-col gap-2.5 pl-6">
<li>
<NavLink
to="/forms/form-elements"
to="/logs/stations"
className={({ isActive }) =>
'group relative flex items-center gap-2.5 rounded-md px-4 font-medium text-bodydark2 duration-300 ease-in-out hover:text-white ' +
(isActive && '!text-white')
}
>
Form Elements
{t('pages.stations')}
</NavLink>
</li>
<li>
<NavLink
to="/forms/form-layout"
to="/logs/trains"
className={({ isActive }) =>
'group relative flex items-center gap-2.5 rounded-md px-4 font-medium text-bodydark2 duration-300 ease-in-out hover:text-white ' +
(isActive && '!text-white')
}
>
Form Layout
{t('pages.trains')}
</NavLink>
</li>
</ul>
@ -356,45 +190,85 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen }: SidebarProps) => {
);
}}
</SidebarLinkGroup>
{/* <!-- Menu Item Forms --> */}
{/* <!-- Menu Item Tables --> */}
<li>
<NavLink
to="/tables"
className={`group relative flex items-center gap-2.5 rounded-sm py-2 px-4 font-medium text-bodydark1 duration-300 ease-in-out hover:bg-graydark dark:hover:bg-meta-4 ${
pathname.includes('tables') && 'bg-graydark dark:bg-meta-4'
}`}
>
<svg
className="fill-current"
width="18"
height="19"
viewBox="0 0 18 19"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_130_9756)">
<path
d="M15.7501 0.55835H2.2501C1.29385 0.55835 0.506348 1.34585 0.506348 2.3021V15.8021C0.506348 16.7584 1.29385 17.574 2.27822 17.574H15.7782C16.7345 17.574 17.5501 16.7865 17.5501 15.8021V2.3021C17.522 1.34585 16.7063 0.55835 15.7501 0.55835ZM6.69385 10.599V6.4646H11.3063V10.5709H6.69385V10.599ZM11.3063 11.8646V16.3083H6.69385V11.8646H11.3063ZM1.77197 6.4646H5.45635V10.5709H1.77197V6.4646ZM12.572 6.4646H16.2563V10.5709H12.572V6.4646ZM2.2501 1.82397H15.7501C16.0313 1.82397 16.2563 2.04897 16.2563 2.33022V5.2271H1.77197V2.3021C1.77197 2.02085 1.96885 1.82397 2.2501 1.82397ZM1.77197 15.8021V11.8646H5.45635V16.3083H2.2501C1.96885 16.3083 1.77197 16.0834 1.77197 15.8021ZM15.7501 16.3083H12.572V11.8646H16.2563V15.8021C16.2563 16.0834 16.0313 16.3083 15.7501 16.3083Z"
fill=""
/>
</g>
<defs>
<clipPath id="clip0_130_9756">
<rect
width="18"
height="18"
fill="white"
transform="translate(0 0.052124)"
/>
</clipPath>
</defs>
</svg>
Tables
</NavLink>
</li>
{/* <!-- Menu Item Tables --> */}
<SidebarLinkGroup
activeCondition={
pathname === '/leaderboard' || pathname.includes('leaderboard')
}
>
{(handleClick, open) => {
return (
<React.Fragment>
<NavLink
to="#"
className={`group relative flex items-center gap-2.5 rounded-sm py-2 px-4 font-medium text-bodydark1 duration-300 ease-in-out hover:bg-graydark dark:hover:bg-meta-4 ${
(pathname === '/leaderboard' ||
pathname.includes('leaderboard')) &&
'bg-graydark dark:bg-meta-4'
}`}
onClick={(e) => {
e.preventDefault();
sidebarExpanded
? handleClick()
: setSidebarExpanded(true);
}}
>
{t('pages.leaderboard')}
<svg
className={`absolute right-4 top-1/2 -translate-y-1/2 fill-current ${
open && 'rotate-180'
}`}
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.41107 6.9107C4.73651 6.58527 5.26414 6.58527 5.58958 6.9107L10.0003 11.3214L14.4111 6.91071C14.7365 6.58527 15.2641 6.58527 15.5896 6.91071C15.915 7.23614 15.915 7.76378 15.5896 8.08922L10.5896 13.0892C10.2641 13.4147 9.73651 13.4147 9.41107 13.0892L4.41107 8.08922C4.08563 7.76378 4.08563 7.23614 4.41107 6.9107Z"
fill=""
/>
</svg>
</NavLink>
{/* <!-- Dropdown Menu Start --> */}
<div
className={`translate transform overflow-hidden ${
!open && 'hidden'
}`}
>
<ul className="mt-4 mb-5.5 flex flex-col gap-2.5 pl-6">
<li>
<NavLink
to="/leaderboard/stations"
className={({ isActive }) =>
'group relative flex items-center gap-2.5 rounded-md px-4 font-medium text-bodydark2 duration-300 ease-in-out hover:text-white ' +
(isActive && '!text-white')
}
>
{t('pages.stations')}
</NavLink>
</li>
<li>
<NavLink
to="/leaderboard/trains"
className={({ isActive }) =>
'group relative flex items-center gap-2.5 rounded-md px-4 font-medium text-bodydark2 duration-300 ease-in-out hover:text-white ' +
(isActive && '!text-white')
}
>
{t('pages.trains')}
</NavLink>
</li>
</ul>
</div>
{/* <!-- Dropdown Menu End --> */}
</React.Fragment>
);
}}
</SidebarLinkGroup>
{/* <!-- Menu Item Settings --> */}
<li>

View File

@ -21,5 +21,13 @@
"version": "Wersja:",
"commit": "Commit:"
}
},
"pages": {
"home": "Strona główna",
"logs": "Logi",
"stations": "Stacje",
"trains": "Pociągi",
"leaderboard": "Tablica wyników"
}
}

View File

@ -0,0 +1,21 @@
import TableOne from '../components/Tables/TableOne';
import TableThree from '../components/Tables/TableThree';
import TableTwo from '../components/Tables/TableTwo';
import { TTrainRecord } from '../types/train.ts';
const trains: TTrainRecord[] = {"success":true,"data":{"records":[{"id":"16b54f4a-0826-4005-b67d-2ab57d74ffeb","steam":"76561199101984415","steamName":"tomsobczak35","trainTime":4841000336,"trainPoints":572048,"trainDistance":8066546,"dispatcherTime":0,"trainStats":{"Pendolino (ED250)":{"distance":8066546,"score":572048,"time":4841000336}}},{"id":"a9050fd0-f3cd-45c9-8087-44948da79b00","steam":"76561198258359953","steamName":"Kashameister.","trainTime":4838762785,"trainPoints":353232,"trainDistance":10274248,"dispatcherTime":0,"trainStats":{"EU07":{"distance":10274248,"score":353232,"time":4838762785}}},{"id":"2a08cadb-bacb-494a-8d09-0ef1870f1057","steam":"76561198200906855","steamName":"Nesto Ash Leo","trainTime":4411743671,"trainPoints":110438,"trainDistance":4412798,"dispatcherTime":0,"trainStats":{"EP08":{"distance":4412798,"score":110438,"time":4411743671}}},{"id":"23de2c57-84da-4845-b901-a40b6b5e1261","steam":"76561199065951587","steamName":"Pablo","trainTime":3021172809,"trainPoints":55277,"trainDistance":429106,"dispatcherTime":250586,"trainStats":{"EN96":{"distance":429106,"score":55277,"time":3021172809}},"dispatcherStats":{"Korytów":{"time":22064},"Olszamowice":{"time":221137},"Dąbrowa Górnicza":{"time":7385}}},{"id":"b44b2b4b-476a-4e52-b612-573d5c5eea78","steam":"76561198356160006","steamName":"Marcion","trainTime":9571588,"dispatcherTime":0,"trainStats":{"Pendolino (ED250)":{"distance":303450,"score":9856,"time":9571588}},"trainDistance":303450,"trainPoints":9856},{"id":"3ee1f655-8329-4c83-96ae-bcf162d31f78","steam":"76561199465955782","steamName":"Bolek","trainTime":14441779,"dispatcherTime":0,"trainStats":{"Pendolino (ED250)":{"distance":402970,"score":9740,"time":14441779}},"trainDistance":402970,"trainPoints":9740},{"id":"c3731119-72b0-47c4-a047-70315e595d01","steam":"76561198048854814","steamName":"Night King_UA","trainTime":9537157,"dispatcherTime":0,"trainStats":{"Pendolino (ED250)":{"distance":302954,"score":9686,"time":9537157}},"trainDistance":302954,"trainPoints":9686},{"id":"a88f7594-844b-47e1-b657-d6c0be2d021a","steam":"76561198886710784","steamName":"LIPTON2315","trainTime":10820008,"dispatcherTime":0,"trainStats":{"EP08":{"distance":240000,"score":0,"time":9860788},"Pendolino (ED250)":{"distance":22693,"score":9320,"time":959220}},"trainDistance":262693,"trainPoints":9320},{"id":"42b5c7f0-3af4-4305-aca7-6462e5bf134b","steam":"76561198067997310","steamName":"Gladicek","trainTime":8042564,"dispatcherTime":0,"trainStats":{"EU07":{"distance":97165,"score":0,"time":4419762},"Traxx (E186)":{"distance":5704,"score":4483,"time":873122},"EN57":{"distance":27186,"score":4696,"time":2262371},"EN96":{"distance":3506,"score":0,"time":487309}},"trainDistance":133561,"trainPoints":9179},{"id":"31a65828-3e87-4123-b8c7-c2604375e5a4","steam":"76561198859961880","steamName":"mpapa","trainTime":15313091,"dispatcherTime":0,"trainStats":{"EP08":{"distance":110491,"score":4463,"time":13036616},"Dragon2 (E6ACTa, E6ACTadb)":{"distance":924,"score":0,"time":321162},"Pendolino (ED250)":{"distance":59999,"score":2750,"time":1955313}},"trainDistance":171414,"trainPoints":7213}]},"code":200}.data.records;
export const TrainLogs = () => {
return (
<>
<div className="flex flex-col gap-10">
<TableOne />
<TableTwo />
<TableThree />
</div>
</>
);
};

View File

@ -0,0 +1,31 @@
export interface TTrainResponse {
success: boolean;
data: TTrainData;
code: number;
}
export interface TTrainData {
records: TTrainRecord[];
}
export interface TTrainRecord {
id: string;
steam: string;
steamName: string;
trainTime: number;
trainPoints: number;
trainDistance: number;
dispatcherTime: number;
trainStats: { [key: string]: TTrainStat };
dispatcherStats?: { [key: string]: TDispatcherStat };
}
export interface TDispatcherStat {
time: number;
}
export interface TTrainStat {
distance: number;
score: number;
time: number;
}