move context menus and rewrite some components from react classes to hooks
This commit is contained in:
parent
c11976cdca
commit
a60242617d
|
@ -7,11 +7,13 @@
|
||||||
|
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
|
import { dateToString } from '../core/utils';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adds customizeable timeout to fetch
|
* Adds customizeable timeout to fetch
|
||||||
* defaults to 8s
|
* defaults to 8s
|
||||||
*/
|
*/
|
||||||
async function fetchWithTimeout(resource, options) {
|
async function fetchWithTimeout(resource, options = {}) {
|
||||||
const { timeout = 8000 } = options;
|
const { timeout = 8000 } = options;
|
||||||
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
|
@ -189,6 +191,26 @@ export async function requestSolveCaptcha(text) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function requestHistoricalTimes(day, canvasId) {
|
||||||
|
try {
|
||||||
|
const date = dateToString(day);
|
||||||
|
const url = `api/history?day=${date}&id=${canvasId}`;
|
||||||
|
const response = await fetchWithTimeout(url);
|
||||||
|
if (response.status !== 200) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const times = await response.json();
|
||||||
|
const parsedTimes = times
|
||||||
|
.map((a) => `${a.substr(0, 2)}:${a.substr(-2, 2)}`);
|
||||||
|
return [
|
||||||
|
'00:00',
|
||||||
|
...parsedTimes,
|
||||||
|
];
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function requestPasswordChange(newPassword, password) {
|
export function requestPasswordChange(newPassword, password) {
|
||||||
return makeAPIPOSTRequest(
|
return makeAPIPOSTRequest(
|
||||||
'api/auth/change_passwd',
|
'api/auth/change_passwd',
|
||||||
|
@ -202,13 +224,6 @@ export async function requestResendVerify() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function requestMcLink(accepted) {
|
|
||||||
return makeAPIPOSTRequest(
|
|
||||||
'api/auth/mclink',
|
|
||||||
{ accepted },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function requestNameChange(name) {
|
export function requestNameChange(name) {
|
||||||
return makeAPIPOSTRequest(
|
return makeAPIPOSTRequest(
|
||||||
'api/auth/change_name',
|
'api/auth/change_name',
|
||||||
|
|
|
@ -421,15 +421,6 @@ export function setName(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setMinecraftName(
|
|
||||||
minecraftname: string,
|
|
||||||
): Action {
|
|
||||||
return {
|
|
||||||
type: 'SET_MINECRAFT_NAME',
|
|
||||||
minecraftname,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setMailreg(
|
export function setMailreg(
|
||||||
mailreg: boolean,
|
mailreg: boolean,
|
||||||
): Action {
|
): Action {
|
||||||
|
|
|
@ -132,7 +132,6 @@ export type Action =
|
||||||
| { type: 'LOGOUT' }
|
| { type: 'LOGOUT' }
|
||||||
| { type: 'RECEIVE_STATS', totalRanking: Object, totalDailyRanking: Object }
|
| { type: 'RECEIVE_STATS', totalRanking: Object, totalDailyRanking: Object }
|
||||||
| { type: 'SET_NAME', name: string }
|
| { type: 'SET_NAME', name: string }
|
||||||
| { type: 'SET_MINECRAFT_NAME', minecraftname: string }
|
|
||||||
| { type: 'SET_MAILREG', mailreg: boolean }
|
| { type: 'SET_MAILREG', mailreg: boolean }
|
||||||
| { type: 'REM_FROM_MESSAGES', message: string }
|
| { type: 'REM_FROM_MESSAGES', message: string }
|
||||||
| { type: 'SHOW_CONTEXT_MENU',
|
| { type: 'SHOW_CONTEXT_MENU',
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable jsx-a11y/no-autofocus */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
|
@ -96,6 +98,7 @@ const Captcha = ({ callback, close }) => {
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
autoCapitalize="off"
|
autoCapitalize="off"
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
|
autoFocus
|
||||||
style={{
|
style={{
|
||||||
width: '6em',
|
width: '6em',
|
||||||
fontSize: 21,
|
fontSize: 21,
|
||||||
|
|
|
@ -2,276 +2,159 @@
|
||||||
* LogIn Form
|
* LogIn Form
|
||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React, {
|
||||||
import { connect } from 'react-redux';
|
useState, useCallback, useRef,
|
||||||
|
} from 'react';
|
||||||
|
import { useSelector, shallowEqual, useDispatch } from 'react-redux';
|
||||||
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import type { State } from '../reducers';
|
import { dateToString } from '../core/utils';
|
||||||
import { selectHistoricalTime } from '../actions';
|
import { selectHistoricalTime } from '../actions';
|
||||||
|
import { requestHistoricalTimes } from '../actions/fetch';
|
||||||
|
|
||||||
function dateToString(date) {
|
|
||||||
// YYYY-MM-DD
|
function stringToDate(dateString) {
|
||||||
const timeString = date.substr(0, 4) + date.substr(5, 2) + date.substr(8, 2);
|
if (!dateString) return null;
|
||||||
// YYYYMMDD
|
|
||||||
return timeString;
|
|
||||||
}
|
|
||||||
function stringToDate(timeString) {
|
|
||||||
// YYYYMMDD
|
// YYYYMMDD
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
const date = `${timeString.substr(0, 4)}-${timeString.substr(4, 2)}-${timeString.substr(6, 2)}`;
|
return `${dateString.substr(0, 4)}-${dateString.substr(4, 2)}-${dateString.substr(6, 2)}`;
|
||||||
// YYYY-MM-DD
|
|
||||||
return date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTimes(day, canvasId) {
|
function stringToTime(timeString) {
|
||||||
try {
|
if (!timeString) return null;
|
||||||
const date = dateToString(day);
|
return `${timeString.substr(0, 2)}:${timeString.substr(2, 2)}`;
|
||||||
const response = await fetch(`./api/history?day=${date}&id=${canvasId}`);
|
|
||||||
if (response.status !== 200) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const times = await response.json();
|
|
||||||
const parsedTimes = times
|
|
||||||
.map((a) => `${a.substr(0, 2)}:${a.substr(-2, 2)}`);
|
|
||||||
return [
|
|
||||||
'00:00',
|
|
||||||
...parsedTimes,
|
|
||||||
];
|
|
||||||
} catch {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class HistorySelect extends React.Component {
|
function getToday() {
|
||||||
constructor() {
|
const date = new Date();
|
||||||
super();
|
let day = date.getDate();
|
||||||
|
let month = date.getMonth() + 1;
|
||||||
const date = new Date();
|
if (month < 10) month = `0${month}`;
|
||||||
let day = date.getDate();
|
if (day < 10) day = `0${day}`;
|
||||||
let month = date.getMonth() + 1;
|
return `${date.getFullYear()}-${month}-${day}`;
|
||||||
if (month < 10) month = `0${month}`;
|
|
||||||
if (day < 10) day = `0${day}`;
|
|
||||||
const max = `${date.getFullYear()}-${month}-${day}`;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
submitting: false,
|
|
||||||
selectedDate: null,
|
|
||||||
selectedTime: null,
|
|
||||||
times: [],
|
|
||||||
max,
|
|
||||||
};
|
|
||||||
this.dateSelect = null;
|
|
||||||
|
|
||||||
this.handleDateChange = this.handleDateChange.bind(this);
|
|
||||||
this.handleTimeChange = this.handleTimeChange.bind(this);
|
|
||||||
this.changeTime = this.changeTime.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleDateChange(evt) {
|
|
||||||
const {
|
|
||||||
submitting,
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
if (submitting) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
submitting: true,
|
|
||||||
times: [],
|
|
||||||
selectedTime: null,
|
|
||||||
});
|
|
||||||
const {
|
|
||||||
canvasId,
|
|
||||||
setTime,
|
|
||||||
} = this.props;
|
|
||||||
const date = evt.target.value;
|
|
||||||
const times = await getTimes(date, canvasId);
|
|
||||||
if (times.length === 0) {
|
|
||||||
this.setState({
|
|
||||||
submitting: false,
|
|
||||||
selectedDate: null,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setTime(date, times[0]);
|
|
||||||
this.setState({
|
|
||||||
submitting: false,
|
|
||||||
selectedDate: date,
|
|
||||||
selectedTime: (times) ? times[0] : null,
|
|
||||||
times,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTimeChange(evt) {
|
|
||||||
const {
|
|
||||||
setTime,
|
|
||||||
} = this.props;
|
|
||||||
const {
|
|
||||||
selectedDate,
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const selectedTime = evt.target.value;
|
|
||||||
this.setState({
|
|
||||||
selectedTime,
|
|
||||||
});
|
|
||||||
setTime(selectedDate, selectedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
async changeTime(diff) {
|
|
||||||
let {
|
|
||||||
times,
|
|
||||||
selectedDate,
|
|
||||||
selectedTime,
|
|
||||||
} = this.state;
|
|
||||||
if (!selectedTime || times.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
setTime,
|
|
||||||
canvasId,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
let newPos = times.indexOf(selectedTime) + diff;
|
|
||||||
if (newPos >= times.length || newPos < 0) {
|
|
||||||
if (newPos < 0) {
|
|
||||||
this.dateSelect.stepDown(1);
|
|
||||||
} else {
|
|
||||||
this.dateSelect.stepUp(1);
|
|
||||||
}
|
|
||||||
selectedDate = this.dateSelect.value;
|
|
||||||
this.setState({
|
|
||||||
submitting: true,
|
|
||||||
times: [],
|
|
||||||
selectedTime: null,
|
|
||||||
});
|
|
||||||
times = await getTimes(selectedDate, canvasId);
|
|
||||||
if (times.length === 0) {
|
|
||||||
this.setState({
|
|
||||||
submitting: false,
|
|
||||||
selectedDate: null,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
submitting: false,
|
|
||||||
selectedDate,
|
|
||||||
});
|
|
||||||
newPos = (newPos < 0) ? (times.length - 1) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedTime = times[newPos];
|
|
||||||
this.setState({
|
|
||||||
times,
|
|
||||||
selectedTime,
|
|
||||||
});
|
|
||||||
setTime(selectedDate, selectedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
canvasStartDate,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const {
|
|
||||||
submitting,
|
|
||||||
max,
|
|
||||||
} = this.state;
|
|
||||||
let {
|
|
||||||
times,
|
|
||||||
selectedDate,
|
|
||||||
selectedTime,
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
if (!selectedDate) {
|
|
||||||
const {
|
|
||||||
historicalDate,
|
|
||||||
historicalTime,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if (historicalDate && historicalTime) {
|
|
||||||
selectedDate = stringToDate(historicalDate);
|
|
||||||
selectedTime = historicalTime;
|
|
||||||
times = [historicalTime];
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
selectedDate,
|
|
||||||
selectedTime,
|
|
||||||
times,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div id="historyselect">
|
|
||||||
<input
|
|
||||||
type="date"
|
|
||||||
requiredPattern="\d{4}-\d{2}-\d{2}"
|
|
||||||
value={selectedDate}
|
|
||||||
min={canvasStartDate}
|
|
||||||
max={max}
|
|
||||||
ref={(ref) => { this.dateSelect = ref; }}
|
|
||||||
onChange={this.handleDateChange}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
{ (selectedTime)
|
|
||||||
? (
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="hsar"
|
|
||||||
onClick={() => this.changeTime(-1)}
|
|
||||||
>←</button>
|
|
||||||
<select
|
|
||||||
value={selectedTime}
|
|
||||||
onChange={this.handleTimeChange}
|
|
||||||
>
|
|
||||||
{times.map((value) => (
|
|
||||||
<option
|
|
||||||
value={value}
|
|
||||||
selected={value === selectedTime}
|
|
||||||
>
|
|
||||||
{value}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="hsar"
|
|
||||||
onClick={() => this.changeTime(+1)}
|
|
||||||
>→</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
: null }
|
|
||||||
{ (submitting) ? <p>Loading...</p> : null }
|
|
||||||
{ (!selectedDate && !submitting) ? <p>Select Date above</p> : null }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HistorySelect = () => {
|
||||||
|
const dateSelect = useRef(null);
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const [submitting, setSubmitting] = useState(false);
|
||||||
return {
|
const [times, setTimes] = useState([]);
|
||||||
setTime(date: string, time: string) {
|
const [max] = useState(getToday());
|
||||||
const timeString = time.substr(0, 2) + time.substr(-2, 2);
|
|
||||||
const dateString = dateToString(date);
|
|
||||||
dispatch(selectHistoricalTime(dateString, timeString));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps(state: State) {
|
const [
|
||||||
const {
|
|
||||||
canvasId,
|
canvasId,
|
||||||
canvasStartDate,
|
canvasStartDate,
|
||||||
historicalDate,
|
historicalDate,
|
||||||
historicalTime,
|
historicalTime,
|
||||||
} = state.canvas;
|
] = useSelector((state) => [
|
||||||
return {
|
state.canvas.canvasId,
|
||||||
canvasId, canvasStartDate, historicalDate, historicalTime,
|
state.canvas.canvasStartDate,
|
||||||
};
|
state.canvas.historicalDate,
|
||||||
}
|
state.canvas.historicalTime,
|
||||||
|
], shallowEqual);
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(HistorySelect);
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const setTime = useCallback((date, time) => {
|
||||||
|
const timeString = time.substr(0, 2) + time.substr(-2, 2);
|
||||||
|
const dateString = dateToString(date);
|
||||||
|
dispatch(selectHistoricalTime(dateString, timeString));
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
const handleDateChange = useCallback(async (evt) => {
|
||||||
|
if (submitting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSubmitting(true);
|
||||||
|
const date = evt.target.value;
|
||||||
|
const newTimes = await requestHistoricalTimes(date, canvasId);
|
||||||
|
if (newTimes && newTimes.length) {
|
||||||
|
setTimes(newTimes);
|
||||||
|
setTime(date, newTimes[0]);
|
||||||
|
}
|
||||||
|
setSubmitting(false);
|
||||||
|
}, [submitting, times]);
|
||||||
|
|
||||||
|
const changeTime = useCallback(async (diff) => {
|
||||||
|
if (!times.length
|
||||||
|
|| !dateSelect || !dateSelect.current || !dateSelect.current.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let newTimes = times;
|
||||||
|
let newPos = times.indexOf(stringToTime(historicalTime)) + diff;
|
||||||
|
let newSelectedDate = dateSelect.current.value;
|
||||||
|
if (newPos >= times.length || newPos < 0) {
|
||||||
|
setSubmitting(true);
|
||||||
|
if (newPos < 0) {
|
||||||
|
dateSelect.current.stepDown(1);
|
||||||
|
} else {
|
||||||
|
dateSelect.current.stepUp(1);
|
||||||
|
}
|
||||||
|
newSelectedDate = dateSelect.current.value;
|
||||||
|
newTimes = await requestHistoricalTimes(
|
||||||
|
newSelectedDate,
|
||||||
|
canvasId,
|
||||||
|
);
|
||||||
|
setSubmitting(false);
|
||||||
|
if (!newTimes || !newTimes.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
newPos = (newPos < 0) ? (newTimes.length - 1) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimes(newTimes);
|
||||||
|
setTime(newSelectedDate, newTimes[newPos]);
|
||||||
|
}, [historicalTime, times, submitting]);
|
||||||
|
|
||||||
|
const selectedDate = stringToDate(historicalDate);
|
||||||
|
const selectedTime = stringToTime(historicalTime);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="historyselect">
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
requiredPattern="\d{4}-\d{2}-\d{2}"
|
||||||
|
value={selectedDate}
|
||||||
|
min={canvasStartDate}
|
||||||
|
max={max}
|
||||||
|
ref={dateSelect}
|
||||||
|
onChange={handleDateChange}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
{ (!!times.length && historicalTime && !submitting)
|
||||||
|
&& (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="hsar"
|
||||||
|
onClick={() => changeTime(-1)}
|
||||||
|
>←</button>
|
||||||
|
<select
|
||||||
|
value={selectedTime}
|
||||||
|
onChange={(evt) => setTime(selectedDate, evt.target.value)}
|
||||||
|
>
|
||||||
|
{times.map((value) => (
|
||||||
|
<option
|
||||||
|
value={value}
|
||||||
|
selected={value === selectedTime}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="hsar"
|
||||||
|
onClick={() => changeTime(+1)}
|
||||||
|
>→</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{ (submitting) && <p>{`${t`Loading`}...`}</p> }
|
||||||
|
{ (!times.length && !submitting) && <p>{t`Select Date above`}</p> }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(HistorySelect);
|
||||||
|
|
|
@ -15,8 +15,8 @@ import Palette from './Palette';
|
||||||
import Alert from './Alert';
|
import Alert from './Alert';
|
||||||
import HistorySelect from './HistorySelect';
|
import HistorySelect from './HistorySelect';
|
||||||
import Mobile3DControls from './Mobile3DControls';
|
import Mobile3DControls from './Mobile3DControls';
|
||||||
import UserContextMenu from './UserContextMenu';
|
import UserContextMenu from './contextmenus/UserContextMenu';
|
||||||
import ChannelContextMenu from './ChannelContextMenu';
|
import ChannelContextMenu from './contextmenus/ChannelContextMenu';
|
||||||
|
|
||||||
|
|
||||||
const CONTEXT_MENUS = {
|
const CONTEXT_MENUS = {
|
||||||
|
|
|
@ -2,170 +2,65 @@
|
||||||
* Messages on top of UserArea
|
* Messages on top of UserArea
|
||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import { setMinecraftName, remFromMessages } from '../actions';
|
import { requestResendVerify } from '../actions/fetch';
|
||||||
import { requestResendVerify, requestMcLink } from '../actions/fetch';
|
|
||||||
|
|
||||||
|
|
||||||
class UserMessages extends React.Component {
|
const UserMessages = () => {
|
||||||
constructor() {
|
const [resentVerify, setResentVerify] = useState(false);
|
||||||
super();
|
const [verifyAnswer, setVerifyAnswer] = useState(null);
|
||||||
this.state = {
|
|
||||||
resentVerify: false,
|
|
||||||
sentLink: false,
|
|
||||||
verifyAnswer: null,
|
|
||||||
linkAnswer: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.submitResendVerify = this.submitResendVerify.bind(this);
|
const messages = useSelector((state) => state.user.messages);
|
||||||
this.submitMcLink = this.submitMcLink.bind(this);
|
|
||||||
|
if (!messages) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async submitResendVerify() {
|
return (
|
||||||
const { resentVerify } = this.state;
|
<div style={{ paddingLeft: '5%', paddingRight: '5%' }}>
|
||||||
if (resentVerify) return;
|
{messages.includes('not_verified')
|
||||||
this.setState({
|
&& messages.splice(messages.indexOf('not_verified'), 1)
|
||||||
resentVerify: true,
|
&& (
|
||||||
});
|
<p className="usermessages">
|
||||||
|
{t`Please verify your mail address
|
||||||
|
or your account could get deleted after a few days.`}
|
||||||
|
{(verifyAnswer)
|
||||||
|
? (
|
||||||
|
<span
|
||||||
|
className="modallink"
|
||||||
|
>
|
||||||
|
{verifyAnswer}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<span
|
||||||
|
role="button"
|
||||||
|
tabIndex={-1}
|
||||||
|
className="modallink"
|
||||||
|
onClick={async () => {
|
||||||
|
if (resentVerify) return;
|
||||||
|
setResentVerify(true);
|
||||||
|
const { errors } = await requestResendVerify();
|
||||||
|
const answer = (errors)
|
||||||
|
? errors[0]
|
||||||
|
: t`A new verification mail is getting sent to you.`;
|
||||||
|
setVerifyAnswer(answer);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t`Click here to request a new verification mail.`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{messages.map((message) => {
|
||||||
|
if (message === 'not_verified') return null;
|
||||||
|
return <p className="usermessages" key={message}>{message}</p>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const { errors } = await requestResendVerify();
|
export default React.memo(UserMessages);
|
||||||
|
|
||||||
const verifyAnswer = (errors)
|
|
||||||
? errors[0]
|
|
||||||
: t`A new verification mail is getting sent to you.`;
|
|
||||||
this.setState({
|
|
||||||
verifyAnswer,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async submitMcLink(accepted) {
|
|
||||||
const { sentLink } = this.state;
|
|
||||||
if (sentLink) return;
|
|
||||||
this.setState({
|
|
||||||
sentLink: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { errors } = await requestMcLink(accepted);
|
|
||||||
|
|
||||||
if (errors) {
|
|
||||||
this.setState({
|
|
||||||
linkAnswer: errors[0],
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { setMCName, remFromUserMessages } = this.props;
|
|
||||||
if (!accepted) {
|
|
||||||
setMCName(null);
|
|
||||||
}
|
|
||||||
remFromUserMessages('not_mc_verified');
|
|
||||||
this.setState({
|
|
||||||
linkAnswer: (accepted)
|
|
||||||
? t`You successfully linked your mc account.`
|
|
||||||
: t`You denied.`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { messages: messagesr } = this.props;
|
|
||||||
if (!messagesr) return null;
|
|
||||||
// state variable is not allowed to be changed, make copy
|
|
||||||
const messages = [...messagesr];
|
|
||||||
const { verifyAnswer, linkAnswer } = this.state;
|
|
||||||
const { minecraftname } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ paddingLeft: '5%', paddingRight: '5%' }}>
|
|
||||||
{(messages.includes('not_verified')
|
|
||||||
&& messages.splice(messages.indexOf('not_verified'), 1))
|
|
||||||
? (
|
|
||||||
<p className="usermessages">
|
|
||||||
{t`Please verify your mail address
|
|
||||||
or your account could get deleted after a few days.`}
|
|
||||||
{(verifyAnswer)
|
|
||||||
? (
|
|
||||||
<span
|
|
||||||
className="modallink"
|
|
||||||
>
|
|
||||||
{verifyAnswer}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<span
|
|
||||||
role="button"
|
|
||||||
tabIndex={-1}
|
|
||||||
className="modallink"
|
|
||||||
onClick={this.submitResendVerify}
|
|
||||||
>
|
|
||||||
{t`Click here to request a new verification mail.`}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
{(messages.includes('not_mc_verified')
|
|
||||||
&& messages.splice(messages.indexOf('not_mc_verified'), 1))
|
|
||||||
? (
|
|
||||||
<p className="usermessages">
|
|
||||||
{t`You requested to link your mc account ${minecraftname}.`}
|
|
||||||
|
|
||||||
{(linkAnswer)
|
|
||||||
? (
|
|
||||||
<span
|
|
||||||
className="modallink"
|
|
||||||
>
|
|
||||||
{linkAnswer}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<span>
|
|
||||||
<span
|
|
||||||
role="button"
|
|
||||||
tabIndex={-1}
|
|
||||||
className="modallink"
|
|
||||||
onClick={() => {
|
|
||||||
this.submitMcLink(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t`Accept`}
|
|
||||||
</span> or
|
|
||||||
<span
|
|
||||||
role="button"
|
|
||||||
tabIndex={-1}
|
|
||||||
className="modallink"
|
|
||||||
onClick={() => {
|
|
||||||
this.submitMcLink(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t`Deny`}
|
|
||||||
</span>.
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
{messages.map((message) => (
|
|
||||||
<p className="usermessages" key={message}>{message}</p>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
|
||||||
return {
|
|
||||||
setMCName(minecraftname) {
|
|
||||||
dispatch(setMinecraftName(minecraftname));
|
|
||||||
},
|
|
||||||
remFromUserMessages(message) {
|
|
||||||
dispatch(remFromMessages(message));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps(state: State) {
|
|
||||||
const { messages, minecraftname } = state.user;
|
|
||||||
return { messages, minecraftname };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UserMessages);
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ import {
|
||||||
setLeaveChannel,
|
setLeaveChannel,
|
||||||
muteChatChannel,
|
muteChatChannel,
|
||||||
unmuteChatChannel,
|
unmuteChatChannel,
|
||||||
} from '../actions';
|
} from '../../actions';
|
||||||
import type { State } from '../reducers';
|
import type { State } from '../../reducers';
|
||||||
|
|
||||||
const ChannelContextMenu = ({
|
const ChannelContextMenu = ({
|
||||||
xPos,
|
xPos,
|
|
@ -15,7 +15,7 @@ import {
|
||||||
startDm,
|
startDm,
|
||||||
setUserBlock,
|
setUserBlock,
|
||||||
setChatChannel,
|
setChatChannel,
|
||||||
} from '../actions';
|
} from '../../actions';
|
||||||
|
|
||||||
const UserContextMenu = () => {
|
const UserContextMenu = () => {
|
||||||
const wrapperRef = useRef(null);
|
const wrapperRef = useRef(null);
|
|
@ -11,7 +11,7 @@ import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import ChatMessage from '../ChatMessage';
|
import ChatMessage from '../ChatMessage';
|
||||||
import ChannelDropDown from '../ChannelDropDown';
|
import ChannelDropDown from '../contextmenus/ChannelDropDown';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
showUserAreaModal,
|
showUserAreaModal,
|
||||||
|
|
|
@ -38,6 +38,14 @@ export function clamp(n: number, min: number, max: number): number {
|
||||||
return Math.max(min, Math.min(n, max));
|
return Math.max(min, Math.min(n, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert YYYY-MM-DD to YYYYMMDD
|
||||||
|
*/
|
||||||
|
export function dateToString(date: string) {
|
||||||
|
// YYYY-MM-DD
|
||||||
|
return date.substr(0, 4) + date.substr(5, 2) + date.substr(8, 2);
|
||||||
|
}
|
||||||
|
|
||||||
// z is assumed to be height here
|
// z is assumed to be height here
|
||||||
// in ui and rendeer, y is height
|
// in ui and rendeer, y is height
|
||||||
export function getChunkOfPixel(
|
export function getChunkOfPixel(
|
||||||
|
|
|
@ -501,7 +501,7 @@ export default function windows(
|
||||||
const yMax = height - SCREEN_MARGIN_S;
|
const yMax = height - SCREEN_MARGIN_S;
|
||||||
let modified = false;
|
let modified = false;
|
||||||
|
|
||||||
const newWindows = [];
|
let newWindows = [];
|
||||||
for (let i = 0; i < state.windows.length; i += 1) {
|
for (let i = 0; i < state.windows.length; i += 1) {
|
||||||
const win = state.windows[i];
|
const win = state.windows[i];
|
||||||
const {
|
const {
|
||||||
|
@ -525,6 +525,26 @@ export default function windows(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action.type === 'RECEIVE_ME') {
|
||||||
|
const args = { ...state.args };
|
||||||
|
newWindows = newWindows.filter((win) => {
|
||||||
|
if (win.open) return true;
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(
|
||||||
|
`Cleaning up window from previous session: ${win.windowId}`,
|
||||||
|
);
|
||||||
|
delete args[win.windowId];
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
showWindows: true,
|
||||||
|
windows: newWindows,
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
showWindows: true,
|
showWindows: true,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user