Skip to content
This repository was archived by the owner on Apr 18, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7,847 changes: 3,907 additions & 3,940 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"classnames": "^2.2.6",
"howler": "^2.1.1",
"lodash": "latest",
"moment": "^2.24.0",
"prop-types": "latest",
"react": "^16.8.6",
"react-beautiful-dnd": "^10.1.1",
Expand Down
7 changes: 6 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Notifications from "./notifications/Notifications";
import Settings from "./settings/Settings";
import {getParsedTimeRemaining} from "./helper/TimerHelper";
import SoundSelector from "./sound/SoundSelector";
import Toaster from "./toaster/Toaster";
import './App.scss';

class App extends Component {
Expand Down Expand Up @@ -45,6 +46,10 @@ class App extends Component {
</div>
}

{(this.props.settings.devMode) &&
<Toaster/>
}

<Notifications/>

<Settings/>
Expand All @@ -68,7 +73,7 @@ class App extends Component {
<div className="footer__item"/>
<div className="footer__item center">
<h4>Finish sound</h4>
<SoundSelector />
<SoundSelector/>
</div>
</footer>
</div>
Expand Down
5 changes: 5 additions & 0 deletions src/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ const actions = {
CHANGE_USER_NAME: "CHANGE_USER_NAME",
UPDATE_USER_ORDER: "UPDATE_USER_ORDER",

// github
FETCH_RELEASE_COMMITS: "FETCH_RELEASE_COMMITS",
FETCH_RELEASE_COMMITS_SUCCESS: "FETCH_RELEASE_COMMITS_SUCCESS",
REMOVE_TOASTER: "REMOVE_TOASTER",

// sound
PLAY_FINISH_SOUND: "PLAY_FINISH_SOUND",
ASSIGN_FINISH_SOUND: "ASSIGN_FINISH_SOUND",
Expand Down
2 changes: 2 additions & 0 deletions src/rootReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import timer from './timer/timerReducer';
import settings from './settings/settingsReducer';
import users from './user/userReducer';
import sounds from './sound/soundReducer';
import toasters from './toaster/toasterReducer';

export default combineReducers({
settings,
timer,
users,
sounds,
toasters,
});
7 changes: 5 additions & 2 deletions src/store.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import {createStore} from 'redux';
import {applyMiddleware, compose, createStore} from 'redux';
import rootReducer from './rootReducer';
import {persistReducer, persistStore} from 'redux-persist'
import storage from 'redux-persist/lib/storage';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
import thunk from "redux-thunk";
import './index.scss';

const persistConfig = {
Expand All @@ -13,9 +14,11 @@ const persistConfig = {
};

const persistedReducer = persistReducer(persistConfig, rootReducer);
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export const store = createStore(
persistedReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
composeEnhancer(applyMiddleware(thunk)),
);

export const persistor = persistStore(store);
75 changes: 75 additions & 0 deletions src/toaster/Toaster.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, {Component} from 'react';
import {bindActionCreators} from "redux";
import {connect} from "react-redux";
import moment from "moment";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faTimes} from "@fortawesome/free-solid-svg-icons";

import {fetchReleaseCommits, removeToaster} from "./../toaster/toasterActions";
import {aMonthAgo, numberOfMonthsToasterLives} from "./../toaster/toasterReducer";
import './Toaster.scss';

class Toaster extends Component {
state = {
classNames: '',
};

componentDidMount() {
this.props.fetchReleaseCommits();
setTimeout(() => this.setState({classNames: 'show'}), 1000);
}

getPercentageLeftOfToaster = (release) => {
let commitDate = moment(release.date);
return `${(moment.duration(commitDate.diff(aMonthAgo)).asMonths() / numberOfMonthsToasterLives) * 100}%`;
};

render() {
const {toasters} = this.props;

if (toasters && toasters.releases.length) {
return (
<div className="Toaster">
{toasters.releases.map(release =>
<div className={`toaster-item ${this.state.classNames}`}>
<div className="toaster-item__header">
<FontAwesomeIcon
icon={faTimes}
size="1x"
title="Remove message"
className="toaster-item__remove"
onClick={() => this.props.removeToaster(release)}
/>
{moment(release.date).calendar(null, {
lastDay: '[Yesterday at] HH:mm',
sameDay: '[Today at] HH:mm',
nextDay: '[Tomorrow at] HH:mm',
lastWeek: '[Last] dddd [at] HH:mm',
nextWeek: 'dddd [at] HH:mm',
sameElse: 'L'
})}
</div>
<div className="toaster-item__progressbar"
style={{width: this.getPercentageLeftOfToaster(release)}}/>
<div className="toaster-item__message">{release.message}</div>
</div>
)}
</div>
);
}

return null;
}
}

const mapStateToProps = state => ({
toasters: state.toasters,
});

const mapDispatchToProps = dispatch => bindActionCreators({
fetchReleaseCommits,
removeToaster,
}, dispatch);

export const unwrapped = Toaster;
export default connect(mapStateToProps, mapDispatchToProps)(Toaster);
72 changes: 72 additions & 0 deletions src/toaster/Toaster.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
$toasterColor: #e2e2e2;
$toasterColor: #e2e2e2;
$hoverColor: #5093c1;

.Toaster {
position: absolute;
top: 0;
left: 0;
margin: 5px;

.toaster-item {
border-radius: 4px;
transform: translateX(-150%);
margin: 8px;
padding: 4px;
background: $toasterColor;
transition: ease-in-out 1s;
transition-timing-function: cubic-bezier(0, 0, 1, 1);
min-width: 300px;
max-width: 350px;
box-shadow: -3px 6px 12px 0px rgba(0, 0, 0, 0.4);

&:hover {
box-shadow: -3px 6px 16px 2px rgba(0, 0, 0, 0.6);

.toaster-item__progressbar {
background: $hoverColor;
}

.toaster-item__header {
color: $hoverColor;
}
}

&.show {
transform: translateX(0%);
}

.toaster-item__header {
box-sizing: border-box;
padding: 2px;
text-align: left;
font-size: 10pt;
color: rgba(0, 0, 0, 0.3);
border: 0 solid rgba(0, 0, 0, 0.2);
border-bottom-width: 1px;
}

.toaster-item__message {
margin: 4px 0;
padding: 2px;
text-align: left;
color: #6f6f6f;
}

.toaster-item__progressbar {
transition: ease-in-out 0.25s;
position: relative;
height: 1px;
width: 100%;
background: rgba(10, 10, 10, 0.15);
}
}

.toaster-item__remove {
cursor: pointer;
position: absolute;
right: 0;
top: 0;
padding: 8px;
}
}
43 changes: 43 additions & 0 deletions src/toaster/toasterActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import actionTypes from "./../actionTypes";
import moment from "moment";

function mapToToasterMessage(commit) {
return {
date: moment(commit.commit.committer.date).toISOString(),
message: commit.commit.message,
sha: commit.sha,
};
}

async function fetchReleaseIdsFromGithub() {
const releases = await fetch("https://api.github.com/repos/pratterino/mobtimer/tags");
let tags = await releases.json().then(tag => tag);
return tags.map(tag => tag.commit.sha);
}

async function fetchReleaseCommitsFromGithub() {
const idsFromGithub = await fetchReleaseIdsFromGithub();
const commitsRequest = await fetch("https://api.github.com/repos/Pratterino/mobtimer/commits");
const commits = await commitsRequest.json().then(data => data);
const filteredCommits = commits.filter(commit => idsFromGithub.includes(commit.sha));
return filteredCommits
.map(mapToToasterMessage)
.sort((a, b) => a.date > b.date);
}

export const fetchReleaseCommits = () => (dispatch) =>{
fetchReleaseCommitsFromGithub()
.then(commits =>
dispatch(releaseCommitsFetchSuccess(commits)));
};

export const removeToaster = (commit) => ({
type: actionTypes.REMOVE_TOASTER,
date: commit.date,
sha: commit.sha,
});

const releaseCommitsFetchSuccess = (commits) => ({
type: actionTypes.FETCH_RELEASE_COMMITS_SUCCESS,
commits,
});
39 changes: 39 additions & 0 deletions src/toaster/toasterReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import actions from "./../actionTypes";
import moment from "moment";

export const numberOfMonthsToasterLives = 1;
export const aMonthAgo = moment().subtract(numberOfMonthsToasterLives, 'months');

const defaultToasterState = {
dismissedDate: aMonthAgo.toISOString(),
releases: [],
};

export default (state = defaultToasterState, action) => {
switch (action.type) {
case actions.FETCH_RELEASE_COMMITS_SUCCESS:
return {
...state,
releases: [
...action.commits
.filter(commit => {
return (
moment(commit.date).isAfter(moment(state.dismissedDate)) &&
(moment.duration(moment(commit.date).diff(aMonthAgo)).asMonths() / numberOfMonthsToasterLives) > 0
);
})
],
};
case actions.REMOVE_TOASTER:
return {
...state,
dismissedDate: moment(action.date).toISOString(),
releases: [
...state.releases.filter(release => release.sha !== action.sha),
],
};

default:
return state;
}
}