mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
fix(ui): rewrite SilenceProgress component with hooks
This commit is contained in:
committed by
Łukasz Mierzwa
parent
2440b7778e
commit
cd41829a27
@@ -1,7 +1,6 @@
|
||||
import React, { Component } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
import { observable, action } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import { useObserver, useLocalStore } from "mobx-react";
|
||||
|
||||
import moment from "moment";
|
||||
import Moment from "react-moment";
|
||||
@@ -10,86 +9,58 @@ import { APISilence } from "Models/API";
|
||||
|
||||
import "./SilenceProgress.scss";
|
||||
|
||||
const SilenceProgress = observer(
|
||||
class SilenceProgress extends Component {
|
||||
static propTypes = {
|
||||
silence: APISilence.isRequired,
|
||||
};
|
||||
|
||||
progress = observable(
|
||||
{
|
||||
value: 0,
|
||||
calculate(startsAt, endsAt) {
|
||||
const durationDone = moment().unix() - moment(startsAt).unix();
|
||||
const durationTotal = moment(endsAt).unix() - moment(startsAt).unix();
|
||||
const durationPercent = Math.floor(
|
||||
(durationDone / durationTotal) * 100
|
||||
);
|
||||
if (this.value !== durationPercent) {
|
||||
this.value = durationPercent;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
calculate: action.bound,
|
||||
const SilenceProgress = ({ silence }) => {
|
||||
const progress = useLocalStore(() => ({
|
||||
value: 0,
|
||||
calculate(startsAt, endsAt) {
|
||||
const durationDone = moment().unix() - moment(startsAt).unix();
|
||||
const durationTotal = moment(endsAt).unix() - moment(startsAt).unix();
|
||||
const durationPercent = Math.floor((durationDone / durationTotal) * 100);
|
||||
if (this.value !== durationPercent) {
|
||||
this.value = durationPercent;
|
||||
}
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
useEffect(() => {
|
||||
progress.calculate(silence.startsAt, silence.endsAt);
|
||||
|
||||
this.recalculateProgress();
|
||||
this.progressTimer = setInterval(this.recalculateProgress, 30 * 1000);
|
||||
}
|
||||
const timer = setInterval(() => {
|
||||
progress.calculate(silence.startsAt, silence.endsAt);
|
||||
}, 30 * 1000);
|
||||
return () => clearInterval(timer);
|
||||
}, [progress, silence.startsAt, silence.endsAt]);
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.progressTimer);
|
||||
this.progressTimer = null;
|
||||
}
|
||||
|
||||
recalculateProgress = () => {
|
||||
const { silence } = this.props;
|
||||
this.progress.calculate(silence.startsAt, silence.endsAt);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { silence } = this.props;
|
||||
|
||||
// if silence is expired we can skip progress value calculation
|
||||
if (moment(silence.endsAt) < moment()) {
|
||||
return (
|
||||
<span className="badge badge-danger align-text-bottom p-1">
|
||||
Expired <Moment fromNow>{silence.endsAt}</Moment>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
let progressClass;
|
||||
if (this.progress.value > 90) {
|
||||
progressClass = "progress-bar bg-danger";
|
||||
} else if (this.progress.value > 75) {
|
||||
progressClass = "progress-bar bg-warning";
|
||||
} else {
|
||||
progressClass = "progress-bar bg-success";
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="badge badge-light nmb-05 align-text-bottom p-1">
|
||||
Expires <Moment fromNow>{silence.endsAt}</Moment>
|
||||
<div className="progress silence-progress">
|
||||
<div
|
||||
className={progressClass}
|
||||
role="progressbar"
|
||||
style={{ width: this.progress.value + "%" }}
|
||||
aria-valuenow={this.progress.value}
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
return useObserver(() =>
|
||||
moment(silence.endsAt) < moment() ? (
|
||||
<span className="badge badge-danger align-text-bottom p-1">
|
||||
Expired <Moment fromNow>{silence.endsAt}</Moment>
|
||||
</span>
|
||||
) : (
|
||||
<span className="badge badge-light nmb-05 align-text-bottom p-1">
|
||||
Expires <Moment fromNow>{silence.endsAt}</Moment>
|
||||
<div className="progress silence-progress">
|
||||
<div
|
||||
className={
|
||||
progress.value > 90
|
||||
? "progress-bar bg-danger"
|
||||
: progress.value > 75
|
||||
? "progress-bar bg-warning"
|
||||
: "progress-bar bg-success"
|
||||
}
|
||||
role="progressbar"
|
||||
style={{ width: progress.value + "%" }}
|
||||
aria-valuenow={progress.value}
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
)
|
||||
);
|
||||
};
|
||||
SilenceProgress.propTypes = {
|
||||
silence: APISilence.isRequired,
|
||||
};
|
||||
|
||||
export { SilenceProgress };
|
||||
|
||||
@@ -2,8 +2,6 @@ import React from "react";
|
||||
|
||||
import { mount } from "enzyme";
|
||||
|
||||
import { toJS } from "mobx";
|
||||
|
||||
import toDiffableHtml from "diffable-html";
|
||||
|
||||
import moment from "moment";
|
||||
@@ -14,6 +12,10 @@ import { SilenceProgress } from "./SilenceProgress";
|
||||
|
||||
let silence;
|
||||
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
silence = MockSilence();
|
||||
|
||||
@@ -57,24 +59,22 @@ describe("<SilenceProgress />", () => {
|
||||
expect(toDiffableHtml(tree.html())).toMatch(/progress-bar bg-success/);
|
||||
});
|
||||
|
||||
it("calling calculate() on progress multiple times in a row doesn't change the value", () => {
|
||||
const startsAt = moment.utc([2000, 0, 1, 0, 0, 0]);
|
||||
const endsAt = moment.utc([2000, 0, 1, 1, 0, 0]);
|
||||
|
||||
it("progressbar is updated every 30 seconds", () => {
|
||||
advanceTo(moment.utc([2000, 0, 1, 0, 30, 0]));
|
||||
const tree = MountedSilenceProgress();
|
||||
const instance = tree.instance();
|
||||
expect(toDiffableHtml(tree.html())).toMatch(/progress-bar bg-success/);
|
||||
|
||||
const value = toJS(instance.progress.value);
|
||||
instance.progress.calculate(startsAt, endsAt);
|
||||
instance.progress.calculate(startsAt, endsAt);
|
||||
instance.progress.calculate(startsAt, endsAt);
|
||||
expect(toJS(instance.progress.value)).toBe(value);
|
||||
advanceTo(moment.utc([2000, 0, 1, 0, 50, 0]));
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(toDiffableHtml(tree.html())).toMatch(/progress-bar bg-warning/);
|
||||
|
||||
advanceTo(moment.utc([2000, 0, 1, 0, 55, 0]));
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(toDiffableHtml(tree.html())).toMatch(/progress-bar bg-danger/);
|
||||
});
|
||||
|
||||
it("resets the timer on unmount", () => {
|
||||
it("unmounts cleanly", () => {
|
||||
const tree = MountedSilenceProgress();
|
||||
expect(tree.instance().progressTimer).not.toBeNull();
|
||||
tree.instance().componentWillUnmount();
|
||||
expect(tree.instance().progressTimer).toBeNull();
|
||||
tree.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user