mirror of
https://git.sr.ht/~ashkeel/strimertul
synced 2024-09-20 02:00:49 +00:00
Timers!
This commit is contained in:
parent
08d3b68f2e
commit
71c0b96091
8 changed files with 192 additions and 72 deletions
|
@ -1,5 +1,5 @@
|
||||||
import { ActionCreatorWithOptionalPayload, AsyncThunk } from '@reduxjs/toolkit';
|
import { ActionCreatorWithOptionalPayload, AsyncThunk } from '@reduxjs/toolkit';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
KilovoltMessage,
|
KilovoltMessage,
|
||||||
|
@ -8,7 +8,6 @@ import {
|
||||||
import { RootState } from '../store';
|
import { RootState } from '../store';
|
||||||
import apiReducer, { getUserPoints } from '../store/api/reducer';
|
import apiReducer, { getUserPoints } from '../store/api/reducer';
|
||||||
import { APIState, LoyaltyStorage } from '../store/api/types';
|
import { APIState, LoyaltyStorage } from '../store/api/types';
|
||||||
import { getInterval } from './time-utils';
|
|
||||||
|
|
||||||
export function useModule<T>({
|
export function useModule<T>({
|
||||||
key,
|
key,
|
||||||
|
|
|
@ -218,7 +218,10 @@
|
||||||
"minimum-delay": "Interval",
|
"minimum-delay": "Interval",
|
||||||
"minimum-delay-help": "How many time must pass between each repeat.",
|
"minimum-delay-help": "How many time must pass between each repeat.",
|
||||||
"minimum-activity": "Minimum chat activity",
|
"minimum-activity": "Minimum chat activity",
|
||||||
"minimum-activity-post": "messages in the last 5 minutes"
|
"minimum-activity-post": "messages in the last 5 minutes",
|
||||||
|
"condition-text": "every {{time}}, at least {{messages}} messages in the last 5 minutes",
|
||||||
|
"err-twitchbot-disabled": "Twitch bot must be enabled in order to use timers!",
|
||||||
|
"enable": "Enable timers"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,40 @@ import React, { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { getInterval } from '../../lib/time-utils';
|
import { getInterval } from '../../lib/time-utils';
|
||||||
|
|
||||||
|
export interface TimeUnit {
|
||||||
|
multiplier: number;
|
||||||
|
unit: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const seconds = { multiplier: 1, unit: 'form-common.time.seconds' };
|
||||||
|
export const minutes = { multiplier: 60, unit: 'form-common.time.minutes' };
|
||||||
|
export const hours = { multiplier: 3600, unit: 'form-common.time.hours' };
|
||||||
|
|
||||||
export interface IntervalProps {
|
export interface IntervalProps {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
value: number;
|
value: number;
|
||||||
min?: number;
|
min?: number;
|
||||||
|
units?: TimeUnit[];
|
||||||
onChange?: (value: number) => void;
|
onChange?: (value: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Interval({ active, value, min, onChange }: IntervalProps) {
|
function Interval({ active, value, min, units, onChange }: IntervalProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const timeUnits = units ?? [seconds, minutes, hours];
|
||||||
|
|
||||||
const [numInitialValue, multInitialValue] = getInterval(value);
|
const [numInitialValue, multInitialValue] = getInterval(value);
|
||||||
const [num, setNum] = useState(numInitialValue);
|
const [num, setNum] = useState(numInitialValue);
|
||||||
const [mult, setMult] = useState(multInitialValue);
|
const [mult, setMult] = useState(multInitialValue);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const seconds = num * mult;
|
const total = num * mult;
|
||||||
if (min && seconds < min) {
|
if (min && total < min) {
|
||||||
setNum(5);
|
const [minNum, minMult] = getInterval(min);
|
||||||
setMult(1);
|
setNum(minNum);
|
||||||
|
setMult(minMult);
|
||||||
}
|
}
|
||||||
onChange(Math.max(min ?? 0, seconds));
|
onChange(Math.max(min ?? 0, total));
|
||||||
}, [num, mult]);
|
}, [num, mult]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -57,9 +70,11 @@ function Interval({ active, value, min, onChange }: IntervalProps) {
|
||||||
setMult(intMult);
|
setMult(intMult);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<option value="1">{t('form-common.time.seconds')}</option>
|
{timeUnits.map((unit) => (
|
||||||
<option value="60">{t('form-common.time.minutes')}</option>
|
<option key={unit.unit} value={unit.multiplier.toString()}>
|
||||||
<option value="3600">{t('form-common.time.hours')}</option>
|
{t(unit.unit)}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -90,7 +90,7 @@ function RewardItem({
|
||||||
{t('actions.test')}
|
{t('actions.test')}
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
<a className="button is-small" onClick={onToggleState}>
|
<a className="button is-small" onClick={onToggleState}>
|
||||||
{t(item.enabled ? 'actions.disable' : 'actions.enable')}
|
{item.enabled ? t('actions.disable') : t('actions.enable')}
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
<a className="button is-small" onClick={onEdit}>
|
<a className="button is-small" onClick={onEdit}>
|
||||||
{t('actions.edit')}
|
{t('actions.edit')}
|
||||||
|
|
|
@ -54,7 +54,7 @@ function CommandItem({
|
||||||
<blockquote>{item.response}</blockquote>
|
<blockquote>{item.response}</blockquote>
|
||||||
<div style={{ marginTop: '1rem' }}>
|
<div style={{ marginTop: '1rem' }}>
|
||||||
<a className="button is-small" onClick={onToggleState}>
|
<a className="button is-small" onClick={onToggleState}>
|
||||||
{item.enabled ? 'Disable' : 'Enable'}
|
{item.enabled ? t('actions.disable') : t('actions.enable')}
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
<a className="button is-small" onClick={onEdit}>
|
<a className="button is-small" onClick={onEdit}>
|
||||||
{t('actions.edit')}
|
{t('actions.edit')}
|
||||||
|
|
|
@ -2,12 +2,13 @@ import { RouteComponentProps } from '@reach/router';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
import prettyTime from 'pretty-ms';
|
||||||
import { useModule } from '../../../lib/react-utils';
|
import { useModule } from '../../../lib/react-utils';
|
||||||
import { modules } from '../../../store/api/reducer';
|
import { modules } from '../../../store/api/reducer';
|
||||||
import Modal from '../../components/Modal';
|
import Modal from '../../components/Modal';
|
||||||
import { TwitchBotTimer } from '../../../store/api/types';
|
import { TwitchBotTimer } from '../../../store/api/types';
|
||||||
import Field from '../../components/Field';
|
import Field from '../../components/Field';
|
||||||
import Interval from '../../components/Interval';
|
import Interval, { hours, minutes } from '../../components/Interval';
|
||||||
|
|
||||||
interface TimerItemProps {
|
interface TimerItemProps {
|
||||||
item: TwitchBotTimer;
|
item: TwitchBotTimer;
|
||||||
|
@ -24,7 +25,14 @@ function TimerItem({ item, onToggleState, onEdit, onDelete }: TimerItemProps) {
|
||||||
<header className="card-header">
|
<header className="card-header">
|
||||||
<div className="card-header-title">
|
<div className="card-header-title">
|
||||||
{item.enabled ? (
|
{item.enabled ? (
|
||||||
<code>{item.name}</code>
|
<>
|
||||||
|
<code>{item.name}</code> (
|
||||||
|
{t('twitch.timers.condition-text', {
|
||||||
|
time: prettyTime(item.minimum_delay * 1000),
|
||||||
|
messages: item.minimum_chat_activity,
|
||||||
|
})}
|
||||||
|
)
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<span className="reward-disabled">
|
<span className="reward-disabled">
|
||||||
<code>{item.name}</code>
|
<code>{item.name}</code>
|
||||||
|
@ -44,12 +52,12 @@ function TimerItem({ item, onToggleState, onEdit, onDelete }: TimerItemProps) {
|
||||||
{expanded ? (
|
{expanded ? (
|
||||||
<div className="content">
|
<div className="content">
|
||||||
{t('twitch.timers.messages')}:{' '}
|
{t('twitch.timers.messages')}:{' '}
|
||||||
{item.messages.map((message) => (
|
{item.messages.map((message, index) => (
|
||||||
<blockquote>{message}</blockquote>
|
<blockquote key={index}>{message}</blockquote>
|
||||||
))}
|
))}
|
||||||
<div style={{ marginTop: '1rem' }}>
|
<div style={{ marginTop: '1rem' }}>
|
||||||
<a className="button is-small" onClick={onToggleState}>
|
<a className="button is-small" onClick={onToggleState}>
|
||||||
{item.enabled ? 'Disable' : 'Enable'}
|
{item.enabled ? t('actions.disable') : t('actions.enable')}
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
<a className="button is-small" onClick={onEdit}>
|
<a className="button is-small" onClick={onEdit}>
|
||||||
{t('actions.edit')}
|
{t('actions.edit')}
|
||||||
|
@ -91,15 +99,16 @@ function TimerModal({
|
||||||
);
|
);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const validForm = name !== '' && messages.length > 0 && messages[0] !== '';
|
const validForm =
|
||||||
|
name !== '' && messages.length > 0 && messages.every((msg) => msg !== '');
|
||||||
|
|
||||||
const confirm = () => {
|
const confirm = () => {
|
||||||
if (onConfirm) {
|
if (onConfirm) {
|
||||||
onConfirm(name, {
|
onConfirm(name, {
|
||||||
name,
|
name,
|
||||||
messages,
|
messages,
|
||||||
minimum_chat_activity: 0,
|
minimum_chat_activity: minActivity,
|
||||||
minimum_delay: 0,
|
minimum_delay: minDelay,
|
||||||
enabled: initialData?.enabled ?? false,
|
enabled: initialData?.enabled ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -126,7 +135,7 @@ function TimerModal({
|
||||||
<Field name={t('twitch.timers.name')} horizontal>
|
<Field name={t('twitch.timers.name')} horizontal>
|
||||||
<div className="field-body">
|
<div className="field-body">
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<p className="control">
|
<div className="control">
|
||||||
<input
|
<input
|
||||||
className={name !== '' ? 'input' : 'input is-danger'}
|
className={name !== '' ? 'input' : 'input is-danger'}
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -134,7 +143,7 @@ function TimerModal({
|
||||||
value={name}
|
value={name}
|
||||||
onChange={(ev) => setName(ev.target.value)}
|
onChange={(ev) => setName(ev.target.value)}
|
||||||
/>
|
/>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Field>
|
</Field>
|
||||||
|
@ -145,7 +154,8 @@ function TimerModal({
|
||||||
value={minDelay}
|
value={minDelay}
|
||||||
onChange={setMinDelay}
|
onChange={setMinDelay}
|
||||||
active={active}
|
active={active}
|
||||||
min={5}
|
min={60}
|
||||||
|
units={[minutes, hours]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -153,7 +163,7 @@ function TimerModal({
|
||||||
<Field name={t('twitch.timers.minimum-activity')} horizontal>
|
<Field name={t('twitch.timers.minimum-activity')} horizontal>
|
||||||
<div className="field-body">
|
<div className="field-body">
|
||||||
<div className="field has-addons" style={{ marginBottom: 0 }}>
|
<div className="field has-addons" style={{ marginBottom: 0 }}>
|
||||||
<p className="control">
|
<div className="control">
|
||||||
<input
|
<input
|
||||||
disabled={!active}
|
disabled={!active}
|
||||||
className="input"
|
className="input"
|
||||||
|
@ -169,7 +179,7 @@ function TimerModal({
|
||||||
setMinActivity(amount);
|
setMinActivity(amount);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</p>
|
</div>
|
||||||
<p className="control">
|
<p className="control">
|
||||||
<a className="button is-static">
|
<a className="button is-static">
|
||||||
{t('twitch.timers.minimum-activity-post')}
|
{t('twitch.timers.minimum-activity-post')}
|
||||||
|
@ -180,18 +190,49 @@ function TimerModal({
|
||||||
</Field>
|
</Field>
|
||||||
<Field name={t('twitch.timers.messages')} horizontal>
|
<Field name={t('twitch.timers.messages')} horizontal>
|
||||||
<div className="field-body">
|
<div className="field-body">
|
||||||
|
<div className="control">
|
||||||
{messages.map((message, index) => (
|
{messages.map((message, index) => (
|
||||||
<div className="field">
|
<div
|
||||||
|
className="field has-addons"
|
||||||
|
key={index}
|
||||||
|
style={{ marginTop: index > 0 ? '0.5rem' : '' }}
|
||||||
|
>
|
||||||
<p className="control">
|
<p className="control">
|
||||||
<textarea
|
<input
|
||||||
className={message !== '' ? 'textarea' : 'textarea is-danger'}
|
|
||||||
placeholder={t('twitch.timers.message-help')}
|
placeholder={t('twitch.timers.message-help')}
|
||||||
onChange={(ev) => setMessageIndex(ev.target.value, index)}
|
onChange={(ev) => setMessageIndex(ev.target.value, index)}
|
||||||
value={message}
|
value={message}
|
||||||
|
className={message !== '' ? 'input' : 'input is-danger'}
|
||||||
|
style={{ width: '28rem' }}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
<p className="control">
|
||||||
|
<button
|
||||||
|
className="button is-danger"
|
||||||
|
onClick={() => {
|
||||||
|
const newMessages = [...messages];
|
||||||
|
newMessages.splice(index, 1);
|
||||||
|
setMessages(newMessages.length > 0 ? newMessages : ['']);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
X
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
<div className="field" style={{ marginTop: '0.5rem' }}>
|
||||||
|
<p className="control">
|
||||||
|
<button
|
||||||
|
className="button is-primary"
|
||||||
|
onClick={() => {
|
||||||
|
setMessages([...messages, '']);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add new
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Field>
|
</Field>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -202,7 +243,11 @@ export default function TwitchBotTimersPage(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
props: RouteComponentProps<unknown>,
|
props: RouteComponentProps<unknown>,
|
||||||
): React.ReactElement {
|
): React.ReactElement {
|
||||||
const [timers, setTimers] = useModule(modules.twitchBotTimers);
|
const [twitchConfig] = useModule(modules.twitchConfig);
|
||||||
|
const [moduleConfig, setModuleConfig] = useModule(
|
||||||
|
modules.twitchBotModulesConfig,
|
||||||
|
);
|
||||||
|
const [timerConfig, setTimerConfig] = useModule(modules.twitchBotTimers);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -211,11 +256,18 @@ export default function TwitchBotTimersPage(
|
||||||
const [timerFilter, setTimerFilter] = useState('');
|
const [timerFilter, setTimerFilter] = useState('');
|
||||||
const timerFilterLC = timerFilter.toLowerCase();
|
const timerFilterLC = timerFilter.toLowerCase();
|
||||||
|
|
||||||
|
const botActive = twitchConfig?.enable_bot ?? false;
|
||||||
|
const timersActive = moduleConfig?.enable_timers ?? false;
|
||||||
|
const active = botActive && timersActive;
|
||||||
|
|
||||||
const createTimer = (name: string, data: TwitchBotTimer): void => {
|
const createTimer = (name: string, data: TwitchBotTimer): void => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setTimers({
|
setTimerConfig({
|
||||||
...timers,
|
...timerConfig,
|
||||||
|
timers: {
|
||||||
|
...timerConfig.timers,
|
||||||
[name]: data,
|
[name]: data,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
setCreateModal(false);
|
setCreateModal(false);
|
||||||
|
@ -227,13 +279,16 @@ export default function TwitchBotTimersPage(
|
||||||
data: TwitchBotTimer,
|
data: TwitchBotTimer,
|
||||||
): void => {
|
): void => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setTimers({
|
setTimerConfig({
|
||||||
...timers,
|
...timerConfig,
|
||||||
|
timers: {
|
||||||
|
...timerConfig.timers,
|
||||||
[oldName]: undefined,
|
[oldName]: undefined,
|
||||||
[newName]: {
|
[newName]: {
|
||||||
...timers[oldName],
|
...timerConfig.timers[oldName],
|
||||||
...data,
|
...data,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
setShowModifyTimer(null);
|
setShowModifyTimer(null);
|
||||||
|
@ -241,31 +296,68 @@ export default function TwitchBotTimersPage(
|
||||||
|
|
||||||
const deleteTimer = (cmd: string): void => {
|
const deleteTimer = (cmd: string): void => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setTimers({
|
setTimerConfig({
|
||||||
...timers,
|
...timerConfig,
|
||||||
|
timers: {
|
||||||
|
...timerConfig.timers,
|
||||||
[cmd]: undefined,
|
[cmd]: undefined,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleTimer = (cmd: string): void => {
|
const toggleTimer = (cmd: string): void => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setTimers({
|
setTimerConfig({
|
||||||
...timers,
|
...timerConfig,
|
||||||
|
timers: {
|
||||||
|
...timerConfig.timers,
|
||||||
[cmd]: {
|
[cmd]: {
|
||||||
...timers[cmd],
|
...timerConfig.timers[cmd],
|
||||||
enabled: !timers[cmd].enabled,
|
enabled: !timerConfig.timers[cmd].enabled,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!botActive) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1 className="title is-4">{t('twitch.timers.header')}</h1>
|
<h1 className="title is-4">{t('twitch.timers.header')}</h1>
|
||||||
|
<p>{t('twitch.timers.err-twitchbot-disabled')}</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1 className="title is-4">{t('twitch.timers.header')}</h1>
|
||||||
|
<Field>
|
||||||
|
<label className="checkbox">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
disabled={!botActive}
|
||||||
|
checked={active}
|
||||||
|
onChange={(ev) =>
|
||||||
|
dispatch(
|
||||||
|
setModuleConfig({
|
||||||
|
...moduleConfig,
|
||||||
|
enable_timers: ev.target.checked,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{` ${t('twitch.timers.enable')} `}
|
||||||
|
</label>
|
||||||
|
</Field>
|
||||||
<div className="field is-grouped">
|
<div className="field is-grouped">
|
||||||
<p className="control">
|
<p className="control">
|
||||||
<button className="button" onClick={() => setCreateModal(true)}>
|
<button
|
||||||
|
className="button"
|
||||||
|
disabled={!timersActive}
|
||||||
|
onClick={() => setCreateModal(true)}
|
||||||
|
>
|
||||||
{t('twitch.timers.new-timer')}
|
{t('twitch.timers.new-timer')}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
|
@ -274,6 +366,7 @@ export default function TwitchBotTimersPage(
|
||||||
<input
|
<input
|
||||||
className="input"
|
className="input"
|
||||||
type="text"
|
type="text"
|
||||||
|
disabled={!timersActive}
|
||||||
placeholder={t('twitch.timers.search')}
|
placeholder={t('twitch.timers.search')}
|
||||||
value={timerFilter}
|
value={timerFilter}
|
||||||
onChange={(ev) => setTimerFilter(ev.target.value)}
|
onChange={(ev) => setTimerFilter(ev.target.value)}
|
||||||
|
@ -297,22 +390,26 @@ export default function TwitchBotTimersPage(
|
||||||
modifyTimer(showModifyTimer, newName, cmdData)
|
modifyTimer(showModifyTimer, newName, cmdData)
|
||||||
}
|
}
|
||||||
initialName={showModifyTimer}
|
initialName={showModifyTimer}
|
||||||
initialData={showModifyTimer ? timers[showModifyTimer] : null}
|
initialData={
|
||||||
|
showModifyTimer ? timerConfig.timers[showModifyTimer] : null
|
||||||
|
}
|
||||||
onClose={() => setShowModifyTimer(null)}
|
onClose={() => setShowModifyTimer(null)}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="reward-list" style={{ marginTop: '1rem' }}>
|
<div className="reward-list" style={{ marginTop: '1rem' }}>
|
||||||
{Object.keys(timers ?? {})
|
{timersActive
|
||||||
|
? Object.keys(timerConfig?.timers ?? {})
|
||||||
?.filter((cmd) => cmd.toLowerCase().includes(timerFilterLC))
|
?.filter((cmd) => cmd.toLowerCase().includes(timerFilterLC))
|
||||||
.map((timer) => (
|
.map((timer) => (
|
||||||
<TimerItem
|
<TimerItem
|
||||||
key={timer}
|
key={timer}
|
||||||
item={timer[timer]}
|
item={timerConfig.timers[timer]}
|
||||||
onDelete={() => deleteTimer(timer)}
|
onDelete={() => deleteTimer(timer)}
|
||||||
onEdit={() => setShowModifyTimer(timer)}
|
onEdit={() => setShowModifyTimer(timer)}
|
||||||
onToggleState={() => toggleTimer(timer)}
|
onToggleState={() => toggleTimer(timer)}
|
||||||
/>
|
/>
|
||||||
))}
|
))
|
||||||
|
: null}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,6 +20,7 @@ func (b *Bot) LoadModules() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cfg.EnableTimers {
|
if cfg.EnableTimers {
|
||||||
|
b.logger.Debug("starting timer module")
|
||||||
b.Timers = SetupTimers(b)
|
b.Timers = SetupTimers(b)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -39,16 +39,20 @@ func SetupTimers(bot *Bot) *BotTimerModule {
|
||||||
mod := &BotTimerModule{
|
mod := &BotTimerModule{
|
||||||
bot: bot,
|
bot: bot,
|
||||||
startTime: time.Now().Round(time.Minute),
|
startTime: time.Now().Round(time.Minute),
|
||||||
|
lastTrigger: make(map[string]time.Time),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load config from database
|
// Load config from database
|
||||||
err := bot.api.db.GetJSON(BotTimersKey, &mod.Config)
|
err := bot.api.db.GetJSON(BotTimersKey, &mod.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
bot.logger.WithError(err).Debug("config load error")
|
||||||
mod.Config = BotTimersConfig{
|
mod.Config = BotTimersConfig{
|
||||||
Timers: make(map[string]BotTimer),
|
Timers: make(map[string]BotTimer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bot.logger.WithField("timers", len(mod.Config.Timers)).Debug("loaded timers")
|
||||||
|
|
||||||
// Start goroutine for clearing message counters and running timers
|
// Start goroutine for clearing message counters and running timers
|
||||||
go mod.runTimers()
|
go mod.runTimers()
|
||||||
|
|
||||||
|
@ -89,11 +93,12 @@ func (m *BotTimerModule) runTimers() {
|
||||||
// Check if enough time has passed
|
// Check if enough time has passed
|
||||||
lastTriggeredTime, ok := m.lastTrigger[name]
|
lastTriggeredTime, ok := m.lastTrigger[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
// If it's the first time we're checking it, start the cooldown
|
||||||
|
lastTriggeredTime = time.Now()
|
||||||
}
|
}
|
||||||
minDelay := timer.MinimumDelay
|
minDelay := timer.MinimumDelay
|
||||||
if minDelay < 5 {
|
if minDelay < 60 {
|
||||||
minDelay = 5
|
minDelay = 60
|
||||||
}
|
}
|
||||||
if now.Sub(lastTriggeredTime) < time.Duration(minDelay)*time.Second {
|
if now.Sub(lastTriggeredTime) < time.Duration(minDelay)*time.Second {
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in a new issue