Client - rename existing front

This commit is contained in:
Sam
2021-09-01 20:08:06 +02:00
parent 6ba3f6d54e
commit 6d1de3c3bb
134 changed files with 0 additions and 0 deletions

View File

@ -1,44 +0,0 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
export default function CustomModal(props) {
const { t } = useTranslation()
return (
<div className="custom-modal-backdrop">
<div className="custom-modal">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">{props.title}</h5>
<button
type="button"
className="close"
aria-label="Close"
onClick={() => props.close()}
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div className="modal-body">
<p>{props.text}</p>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => props.confirm()}
>
{t('common:Yes')}
</button>
<button
type="button"
className="btn btn-secondary"
onClick={() => props.close()}
>
{t('common:No')}
</button>
</div>
</div>
</div>
</div>
)
}

View File

@ -1,45 +0,0 @@
import React from 'react'
import { withTranslation } from 'react-i18next'
import { connect } from 'react-redux'
class CustomTextArea extends React.Component {
constructor(props, context) {
super(props, context)
this.state = {
text: props.defaultValue ? props.defaultValue : '',
}
}
handleOnChange(changeEvent) {
this.setState({ text: changeEvent.target.value })
if (this.props.onTextChange) {
this.props.onTextChange(changeEvent)
}
}
render() {
const { charLimit, loading, name, t } = this.props
const { text } = this.state
return (
<>
<textarea
name={name}
defaultValue={text}
disabled={loading ? loading : false}
className="form-control input-lg"
maxLength={charLimit}
onChange={event => this.handleOnChange(event)}
/>
<div className="remaining-chars">
{t('common:remaining characters')}: {text.length}/{charLimit}
</div>
</>
)
}
}
export default withTranslation()(
connect(state => ({
loading: state.loading,
}))(CustomTextArea)
)

View File

@ -1,33 +0,0 @@
import React from 'react'
export default class Message extends React.PureComponent {
render() {
const { message, messages, t } = this.props
const singleMessage =
message === '' || !message
? ''
: message.split('|').length > 1
? `${t(`messages:${message.split('|')[0]}`)}: ${t(
`messages:${message.split('|')[1]}`
)}`
: t(`messages:${message}`)
return (
<div className="error-message">
{singleMessage !== '' && <code>{singleMessage}</code>}
{messages &&
messages.length > 0 &&
(messages.length === 1 ? (
<code>{messages[0].value}</code>
) : (
<code>
<ul>
{messages.map(msg => (
<li key={msg.id}>{t(`messages:${msg.value}`)}</li>
))}
</ul>
</code>
))}
</div>
)
}
}

View File

@ -1,18 +0,0 @@
import React from 'react'
import { Link } from 'react-router-dom'
export default class NoWorkouts extends React.PureComponent {
render() {
const { t } = this.props
return (
<div className="card text-center">
<div className="card-body">
{t('common:No workouts.')}{' '}
<Link to={{ pathname: '/workouts/add' }}>
{t('dashboard:Upload one !')}
</Link>
</div>
</div>
)
}
}

View File

@ -1,72 +0,0 @@
import React from 'react'
import { Link } from 'react-router-dom'
import { formatUrl, rangePagination } from '../../utils'
export default class Pagination extends React.PureComponent {
getUrl(value) {
const { query, pathname } = this.props
const newQuery = Object.assign({}, query)
let page = query.page ? +query.page : 1
switch (value) {
case 'prev':
page -= 1
break
case 'next':
page += 1
break
default:
page = +value
}
newQuery.page = page
return formatUrl(pathname, newQuery)
}
render() {
const { pagination, t } = this.props
return (
<>
{pagination && Object.keys(pagination).length > 0 && (
<nav aria-label="Page navigation example">
<ul className="pagination justify-content-center">
<li
className={`page-item ${pagination.has_prev ? '' : 'disabled'}`}
>
<Link
className="page-link"
to={this.getUrl('prev')}
aria-disabled={!pagination.has_prev}
>
{t('common:Previous')}
</Link>
</li>
{rangePagination(pagination.pages).map(page => (
<li
key={page}
className={`page-item ${
page === pagination.page ? 'active' : ''
}`}
>
<Link className="page-link" to={this.getUrl(page)}>
{page}
</Link>
</li>
))}
<li
className={`page-item ${pagination.has_next ? '' : 'disabled'}`}
>
<Link
className="page-link"
to={this.getUrl('next')}
aria-disabled={!pagination.has_next}
>
{t('common:Next')}
</Link>
</li>
</ul>
</nav>
)}
</>
)
}
}

View File

@ -1,29 +0,0 @@
import React from 'react'
import { apiUrl } from '../../utils'
export default class StaticMap extends React.PureComponent {
render() {
const { display, workout } = this.props
return (
<div className={`workout-map${display === 'list' ? '-list' : ''}`}>
<img
src={`${apiUrl}workouts/map/${workout.map}?${Date.now()}`}
alt="workout map"
/>
<div className={`map-attribution${display === 'list' ? '-list' : ''}`}>
<span className="map-attribution-text">©</span>
<a
className="map-attribution-text"
href="http://www.openstreetmap.org/copyright"
target="_blank"
rel="noopener noreferrer"
>
OpenStreetMap
</a>
</div>
</div>
)
}
}

View File

@ -1,30 +0,0 @@
import React from 'react'
import { formatValue } from '../../../utils/stats'
/**
* @return {null}
*/
export default function CustomLabel(props) {
const { displayedData, x, y, width, value } = props
if (!value) {
return null
}
const radius = 10
const formattedValue = formatValue(displayedData, value)
return (
<g>
<text
x={x + width / 2}
y={y - radius}
fill="#666"
fontSize="11"
textAnchor="middle"
dominantBaseline="middle"
>
{formattedValue}
</text>
</g>
)
}

View File

@ -1,36 +0,0 @@
import React from 'react'
import { formatDuration } from '../../../utils/stats'
const formatValue = (displayedData, value) =>
displayedData === 'duration'
? formatDuration(value, true)
: ['distance', 'ascent', 'descent'].includes(displayedData)
? value.toFixed(2)
: value
/**
* @return {null}
*/
export default function CustomTooltip(props) {
const { active } = props
if (active) {
const { displayedData, payload, label } = props
let total = 0
payload.map(p => (total += p.value))
return (
<div className="custom-tooltip">
<p className="custom-tooltip-label">{label}</p>
{payload.map(p => (
<p key={p.name} style={{ color: p.fill }}>
{p.name}: {formatValue(displayedData, p.value)} {p.unit}
</p>
))}
{payload.length > 0 && (
<p>Total: {formatValue(displayedData, total)}</p>
)}
</div>
)
}
return null
}

View File

@ -1,122 +0,0 @@
import React from 'react'
import {
Bar,
BarChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts'
import { formatValue } from '../../../utils/stats'
import { workoutColors } from '../../../utils/workouts'
import CustomTooltip from './CustomTooltip'
import CustomLabel from './CustomLabel'
export default class StatsCharts extends React.PureComponent {
constructor(props, context) {
super(props, context)
this.state = {
displayedData: 'distance',
}
}
handleRadioChange(changeEvent) {
this.setState({
displayedData: changeEvent.target.name,
})
}
render() {
const { displayedData } = this.state
const { sports, stats, t, withElevation } = this.props
if (Object.keys(stats).length === 0) {
return t('common:No workouts.')
}
return (
<div className="chart-stats">
<div className="row chart-radio">
<label className="radioLabel col">
<input
type="radio"
name="distance"
checked={displayedData === 'distance'}
onChange={e => this.handleRadioChange(e)}
/>
{t('statistics:distance')}
</label>
<label className="radioLabel col">
<input
type="radio"
name="duration"
checked={displayedData === 'duration'}
onChange={e => this.handleRadioChange(e)}
/>
{t('statistics:duration')}
</label>
{withElevation && (
<>
<label className="radioLabel col">
<input
type="radio"
name="ascent"
checked={displayedData === 'ascent'}
onChange={e => this.handleRadioChange(e)}
/>
{t('statistics:ascent')}
</label>
<label className="radioLabel col">
<input
type="radio"
name="descent"
checked={displayedData === 'descent'}
onChange={e => this.handleRadioChange(e)}
/>
{t('statistics:descent')}
</label>
</>
)}
<label className="radioLabel col">
<input
type="radio"
name="workouts"
checked={displayedData === 'workouts'}
onChange={e => this.handleRadioChange(e)}
/>
{t('statistics:workouts')}
</label>
</div>
<ResponsiveContainer height={300}>
<BarChart data={stats[displayedData]} margin={{ top: 15, bottom: 0 }}>
<XAxis
dataKey="date"
interval={0} // to force to display all ticks
/>
<YAxis tickFormatter={value => formatValue(displayedData, value)} />
<Tooltip
content={<CustomTooltip displayedData={displayedData} />}
/>
{sports.map((s, i) => (
<Bar
// disable for now due to problems w/ CustomLabel
// see https://github.com/recharts/recharts/issues/829
isAnimationActive={false}
key={s.id}
dataKey={s.label}
stackId="a"
fill={workoutColors[i]}
label={
i === sports.length - 1 ? (
<CustomLabel displayedData={displayedData} />
) : (
''
)
}
name={t(`sports:${s.label}`)}
/>
))}
</BarChart>
</ResponsiveContainer>
</div>
)
}
}

View File

@ -1,88 +0,0 @@
import { format } from 'date-fns'
import React from 'react'
import { connect } from 'react-redux'
import { getStats } from '../../../actions/stats'
import { formatStats } from '../../../utils/stats'
import StatsChart from './StatsChart'
class Statistics extends React.PureComponent {
componentDidMount() {
this.updateData()
}
componentDidUpdate(prevProps) {
if (
(this.props.user.username &&
this.props.user.username !== prevProps.user.username) ||
this.props.statsParams !== prevProps.statsParams
) {
this.updateData()
}
}
updateData() {
if (this.props.user.username) {
this.props.loadWorkouts(
this.props.user.username,
this.props.user.weekm,
this.props.statsParams
)
}
}
render() {
const {
displayedSports,
sports,
statistics,
statsParams,
displayEmpty,
t,
user,
withElevation,
} = this.props
if (!displayEmpty && Object.keys(statistics).length === 0) {
return <span>{t('common:No workouts.')}</span>
}
const stats = formatStats(
statistics,
sports,
statsParams,
displayedSports,
user.weekm
)
return (
<StatsChart
sports={sports}
stats={stats}
t={t}
withElevation={withElevation}
/>
)
}
}
export default connect(
state => ({
sports: state.sports.data,
statistics: state.statistics.data,
user: state.user,
}),
dispatch => ({
loadWorkouts: (userName, weekm, data) => {
const dateFormat = 'yyyy-MM-dd'
// depends on user config (first day of week)
const time =
data.duration === 'week'
? `${data.duration}${weekm ? 'm' : ''}`
: data.duration
const params = {
from: format(data.start, dateFormat),
to: format(data.end, dateFormat),
time: time,
}
dispatch(getStats(userName, data.type, params))
},
})
)(Statistics)