qw/timer (#23)
* Rename logo and add 32x32 version * Set timer icon if a timer is running * Do not query activities on initialization * Show timer in bubble if timed activity exists * Pass timed activity to App * Code cleanup * Show timer view and stop timer * Make hours optional * Use booked seconds instead of hours * Add type submit to form button * Define colors as sass variables⎄ * Style timer view * Show start timer submit label * Update view layouts and content * Update version and changelog * Dyanically set iframe height * Reduce h1 font size * Add svg webpack loader * Parse empty string (TimeInputParser) * Forward ref in Popup component * Start time on current day only, format buttons * Improve styling * Set standard height as iframe default height, validate form * Upgrade packages to supress react warning * Show activity form in popup after timer was stoped * Use stop-watch icon in timer view * Fix empty description * Close TimerView if timer stopped for current service * Style timerview * Improve timer view styling * qw/setting-time-tracking-hh-mm (#24) * Format duration depending on settingTimeTrackingHHMM * Fix formatDuation without second argument * Fix time format after updating bubble * Add tests for formatDuration
This commit is contained in:
@@ -1,39 +1,24 @@
|
||||
import React, { Component } from "react"
|
||||
import React, { useEffect, useRef, forwardRef } from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import queryString from "query-string"
|
||||
import { ERROR_UNKNOWN, ERROR_UNAUTHORIZED, ERROR_UPGRADE_REQUIRED, serializeProps } from "utils"
|
||||
import { isChrome } from "utils/browser"
|
||||
import { serializeProps } from "utils"
|
||||
|
||||
function getStyles(errorType) {
|
||||
return {
|
||||
width: "516px",
|
||||
height:
|
||||
errorType === ERROR_UNAUTHORIZED
|
||||
? "834px"
|
||||
: errorType === ERROR_UPGRADE_REQUIRED
|
||||
? isChrome()
|
||||
? "369px"
|
||||
: "461px"
|
||||
: errorType === ERROR_UNKNOWN
|
||||
? "550px"
|
||||
: "558px",
|
||||
}
|
||||
}
|
||||
const Popup = forwardRef((props, ref) => {
|
||||
const iFrameRef = useRef()
|
||||
|
||||
class Popup extends Component {
|
||||
static propTypes = {
|
||||
service: PropTypes.object,
|
||||
errorType: PropTypes.string,
|
||||
onRequestClose: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
handleRequestClose = event => {
|
||||
const handleRequestClose = event => {
|
||||
if (event.target.classList.contains("moco-bx-popup")) {
|
||||
this.props.onRequestClose()
|
||||
props.onRequestClose()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const handleMessage = event => {
|
||||
if (iFrameRef.current && event.data?.__mocoBX?.iFrameHeight > 300) {
|
||||
iFrameRef.current.style.height = `${event.data.__mocoBX.iFrameHeight}px`
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// Document might lose focus when clicking the browser action.
|
||||
// Document might be out of focus when hitting the shortcut key.
|
||||
// This puts the focus back to the document and ensures that:
|
||||
@@ -41,41 +26,47 @@ class Popup extends Component {
|
||||
// - the ESC key closes the popup without closing anything else
|
||||
window.focus()
|
||||
document.activeElement?.blur()
|
||||
}
|
||||
window.addEventListener("message", handleMessage)
|
||||
return () => {
|
||||
window.removeEventListener("message", handleMessage)
|
||||
}
|
||||
}, [])
|
||||
|
||||
render() {
|
||||
const serializedProps = serializeProps([
|
||||
"loading",
|
||||
"service",
|
||||
"subdomain",
|
||||
"lastProjectId",
|
||||
"lastTaskId",
|
||||
"roundTimeEntries",
|
||||
"projects",
|
||||
"activities",
|
||||
"schedules",
|
||||
"lastProjectId",
|
||||
"lastTaskId",
|
||||
"fromDate",
|
||||
"toDate",
|
||||
"errorType",
|
||||
"errorMessage",
|
||||
])(this.props)
|
||||
const serializedProps = serializeProps([
|
||||
"loading",
|
||||
"service",
|
||||
"subdomain",
|
||||
"projects",
|
||||
"activities",
|
||||
"schedules",
|
||||
"timedActivity",
|
||||
"lastProjectId",
|
||||
"lastTaskId",
|
||||
"fromDate",
|
||||
"toDate",
|
||||
"errorType",
|
||||
"errorMessage",
|
||||
])(props)
|
||||
|
||||
const styles = getStyles(this.props.errorType)
|
||||
|
||||
return (
|
||||
<div className="moco-bx-popup" onClick={this.handleRequestClose}>
|
||||
<div className="moco-bx-popup-content" style={styles}>
|
||||
<iframe
|
||||
src={chrome.extension.getURL(`popup.html?${queryString.stringify(serializedProps)}`)}
|
||||
width={styles.width}
|
||||
height={styles.height}
|
||||
/>
|
||||
</div>
|
||||
return (
|
||||
<div ref={ref} className="moco-bx-popup" onClick={handleRequestClose}>
|
||||
<div className="moco-bx-popup-content" style={{ width: "516px" }}>
|
||||
<iframe
|
||||
ref={iFrameRef}
|
||||
src={chrome.extension.getURL(`popup.html?${queryString.stringify(serializedProps)}`)}
|
||||
style={{ width: "516px", height: "576px", transition: "height 0.1s ease-in-out" }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
Popup.displayName = "Popup"
|
||||
|
||||
Popup.propTypes = {
|
||||
service: PropTypes.object,
|
||||
errorType: PropTypes.string,
|
||||
onRequestClose: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default Popup
|
||||
|
||||
Reference in New Issue
Block a user