Skip to content

Commit 5525660

Browse files
committed
add do not disturbe mode
1 parent 793d366 commit 5525660

9 files changed

Lines changed: 221 additions & 34 deletions

File tree

src/App.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { Suspense, useEffect, useLayoutEffect, useState } from 'react'
22
import 'react-contexify/dist/ReactContexify.css'
33
import 'src/assets/App.css'
4-
import { Header } from 'src/components/Layout'
4+
import { Header, PausedAppContent } from 'src/components/Layout'
55
import { BookmarksSidebar } from 'src/features/bookmarks'
66
import { MarketingBanner } from 'src/features/MarketingBanner'
77
import { setupAnalytics, setupIdentification, trackPageView } from 'src/lib/analytics'
@@ -19,7 +19,7 @@ function App() {
1919
const [showSideBar, setShowSideBar] = useState(false)
2020
const [showSettings, setShowSettings] = useState(false)
2121
const [showOnboarding, setShowOnboarding] = useState(true)
22-
const { onboardingCompleted, firstSeenDate, markOnboardingAsCompleted } = useUserPreferences()
22+
const { onboardingCompleted, firstSeenDate, markOnboardingAsCompleted, pauseTo } = useUserPreferences()
2323

2424
useLayoutEffect(() => {
2525
if (!onboardingCompleted && getAppVersion() <= '1.15.9') {
@@ -35,13 +35,18 @@ function App() {
3535
setupAnalytics()
3636
setupIdentification()
3737
trackPageView('home')
38+
3839
}, [])
3940

41+
const isAppPaused = Boolean(pauseTo && pauseTo - (new Date()).getTime() > 0)
42+
console.log("pauseTo: ", isAppPaused);
43+
4044
return (
4145
<>
4246
<MarketingBanner />
4347

4448
<div className="App">
49+
<PausedAppContent isAppPaused={isAppPaused} />
4550
{!onboardingCompleted && isWebOrExtensionVersion() === 'extension' && (
4651
<Suspense fallback={null}>
4752
<OnboardingModal

src/assets/App.css

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,3 +1120,29 @@ Producthunt item
11201120
position: relative;
11211121
vertical-align: middle;
11221122
}
1123+
1124+
/* PAUSE CONTENT */
1125+
1126+
.pauseContentWrapper {
1127+
height: 0;
1128+
transition: height 0.5s ease-out;
1129+
}
1130+
1131+
.pauseContentWrapper.active {
1132+
height: 100vh;
1133+
}
1134+
1135+
.pauseContentWrapper .options {
1136+
height: 5%;
1137+
display: flex;
1138+
justify-content: flex-end;
1139+
align-items: flex-end;
1140+
padding-right: 24px;
1141+
}
1142+
1143+
.pauseContentWrapper .searchContainer {
1144+
height: 95%;
1145+
display: flex;
1146+
justify-content: center;
1147+
align-items: center;
1148+
}

src/components/Elements/SearchBar/SearchBar.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import React, { useEffect, useRef } from 'react'
2-
import { trackSearchEngineUse } from 'src/lib/analytics'
32
import { GoSearch } from 'react-icons/go'
43
import { SUPPORTED_SEARCH_ENGINES } from 'src/config'
4+
import { trackSearchEngineUse } from 'src/lib/analytics'
55
import { useUserPreferences } from 'src/stores/preferences'
66
import { SearchEngine } from 'src/types'
77

8-
export const SearchBar = () => {
8+
type SearchBarProps = {
9+
withLogo?: boolean
10+
}
11+
12+
export const SearchBar = ({ withLogo }: SearchBarProps) => {
913
const { searchEngine } = useUserPreferences()
1014

1115
const keywordsInputRef = useRef<HTMLInputElement | null>(null)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useEffect, useState } from 'react'
2+
import Toggle from 'react-toggle'
3+
import { SearchBar } from 'src/components/Elements/SearchBar'
4+
import { useUserPreferences } from 'src/stores/preferences'
5+
6+
type PausedAppContentProps = {
7+
isAppPaused: boolean
8+
}
9+
10+
export const PausedAppContent = ({ isAppPaused }: PausedAppContentProps) => {
11+
const { setPauseTo } = useUserPreferences()
12+
const [isToggleChecked, setIsToggleChecked] = useState(isAppPaused)
13+
14+
useEffect(() => {
15+
setIsToggleChecked(isAppPaused)
16+
}, [isAppPaused])
17+
18+
const onPauseToggle = () => {
19+
setIsToggleChecked(false)
20+
setTimeout(() => {
21+
setPauseTo(0)
22+
}, 550)
23+
}
24+
const wrapperClassName = `pauseContentWrapper ${isAppPaused ? 'active' : ''}`
25+
26+
return (
27+
<div className={wrapperClassName}>
28+
{isAppPaused && (
29+
<>
30+
<div className="options">
31+
<Toggle checked={isToggleChecked} onChange={onPauseToggle} />
32+
</div>
33+
<div className="searchContainer">
34+
<SearchBar withLogo={true} />
35+
</div>
36+
</>
37+
)}
38+
</div>
39+
)
40+
}

src/components/Layout/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
export * from "./Header"
2-
export * from "./Footer"
3-
export * from "./AppContentLayout"
4-
export * from "./ScrollCardsNavigator"
1+
export * from './AppContentLayout'
2+
export * from './Footer'
3+
export * from './Header'
4+
export * from './PausedAppContent'
5+
export * from './ScrollCardsNavigator'
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { useState } from 'react'
2+
import Select from 'react-select'
3+
import Toggle from 'react-toggle'
4+
5+
type PauseSettingsProps = {
6+
onSubmit: (pauseToValue: number) => void
7+
}
8+
9+
type PauseOptionType = {
10+
value: number
11+
label: string
12+
}
13+
14+
const pauseOptions: PauseOptionType[] = [
15+
{ value: 1, label: 'Minutes' },
16+
{ value: 60, label: 'Hours' },
17+
{ value: 1440, label: 'Days' },
18+
]
19+
20+
export const PauseSettings = ({ onSubmit }: PauseSettingsProps) => {
21+
const [isPauseChecked, setIsPauseChecked] = useState(false)
22+
const [selectedNumber, setSelectedNumber] = useState('')
23+
const [selectedPeriod, setSelectedPeriod] = useState<PauseOptionType>(pauseOptions[0])
24+
25+
const onPauseAppChange = () => {
26+
setIsPauseChecked(!isPauseChecked)
27+
}
28+
const onSubmitClick = () => {
29+
try {
30+
let pauseValue = parseInt(selectedNumber) * selectedPeriod.value
31+
if (pauseValue <= 0) {
32+
throw Error('Invalid value')
33+
}
34+
const futureDate = new Date(new Date().getTime() + pauseValue * 60000)
35+
onSubmit(futureDate.getTime())
36+
} catch (err) {
37+
console.log('PauseSettings Error:', err)
38+
}
39+
}
40+
41+
return (
42+
<div className="settingRow">
43+
<p className="settingTitle">Pause App</p>
44+
<div className="settingContent">
45+
<Toggle checked={isPauseChecked} icons={false} onChange={onPauseAppChange} />
46+
{isPauseChecked && (
47+
<div className="pauseFormWrapper">
48+
<div className="pauseForm">
49+
<input
50+
type="number"
51+
value={selectedNumber}
52+
onChange={(e) => setSelectedNumber(e.target.value)}
53+
// value={rssUrl || ''}
54+
// onChange={(e) => setRssUrl(e.target.value)}
55+
placeholder="Number"
56+
/>
57+
<Select
58+
value={selectedPeriod}
59+
options={pauseOptions}
60+
isClearable={false}
61+
isSearchable={false}
62+
classNamePrefix={'hackertab'}
63+
onChange={(newValue) => setSelectedPeriod(newValue as PauseOptionType)}
64+
/>
65+
</div>
66+
<div className="buttonWrapper">
67+
<button className="pauseButton" onClick={onSubmitClick}>
68+
Done
69+
</button>
70+
</div>
71+
</div>
72+
)}
73+
</div>
74+
</div>
75+
)
76+
}

src/features/settings/components/SettingsModal.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
} from 'src/lib/analytics'
2626
import { useUserPreferences } from 'src/stores/preferences'
2727
import { SearchEngineType, SelectedCard } from 'src/types'
28+
import { PauseSettings } from './PauseSettings'
2829
import { RssSetting } from './RssSetting'
2930
import './settings.css'
3031

@@ -56,6 +57,7 @@ export const SettingsModal = ({ showSettings, setShowSettings }: SettingsModalPr
5657
setTags,
5758
userCustomCards,
5859
setUserCustomCards,
60+
setPauseTo,
5961
} = useUserPreferences()
6062
const [selectedCards, setSelectedCards] = useState(cards)
6163

@@ -144,6 +146,13 @@ export const SettingsModal = ({ showSettings, setShowSettings }: SettingsModalPr
144146
identifyUserTheme(newTheme)
145147
}
146148

149+
const onPauseSubmit = (pauseToValue: number) => {
150+
handleCloseModal()
151+
setTimeout(() => {
152+
setPauseTo(pauseToValue)
153+
}, 250)
154+
}
155+
147156
return (
148157
<ReactModal
149158
isOpen={showSettings}
@@ -215,6 +224,8 @@ export const SettingsModal = ({ showSettings, setShowSettings }: SettingsModalPr
215224

216225
<RssSetting setSelectedCards={setSelectedCards} />
217226

227+
<PauseSettings onSubmit={onPauseSubmit} />
228+
218229
<div className="settingRow">
219230
<p className="settingTitle">Dark Mode</p>
220231
<div className="settingContent">

src/features/settings/components/settings.css

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -177,24 +177,8 @@ Select styles
177177
border-radius: 20px !important;
178178
color: var(--tag-secondary-color) !important;
179179
}
180-
.rss-sources .hackertab__indicators {
181-
display: none;
182-
}
183180

184-
.rss-widget
185-
.rssUrlControl {
186-
margin: 6px 0;
187-
color: var(--primary-text-color);
188-
}
189181

190-
.rssUrlInput {
191-
width: 66%;
192-
margin-right: 4px;
193-
padding: 4px;
194-
background-color: var(--card-background-color) !important;
195-
border-color: var(--tag-border-color) !important;
196-
color: var(--primary-text-color)
197-
}
198182

199183
@media (max-width: 768px) {
200184
.Modal {
@@ -216,3 +200,39 @@ Select styles
216200
align-items: flex-start;
217201
}
218202
}
203+
204+
/* PAUSE SETTING */
205+
206+
207+
.pauseFormWrapper {
208+
margin: 6px 0 0 6px;
209+
}
210+
211+
.pauseForm {
212+
display: flex;
213+
flex-direction: row;
214+
margin-bottom: 8px;
215+
}
216+
217+
.pauseForm input[type=number] {
218+
margin-right: 24px;
219+
flex: 1;
220+
background-color: var(--settings-input-background-color);
221+
border: 1px solid var(--settings-input-border-color);
222+
border-radius: 50px;
223+
padding: 6px 18px;
224+
color: var(--settings-input-text-color);
225+
font-size: 14px;
226+
}
227+
228+
.buttonWrapper {
229+
display: flex;
230+
justify-content: flex-end;
231+
margin-right: 6px;
232+
}
233+
234+
.pauseButton {
235+
236+
background-color: #EE802F;
237+
color: white;
238+
}

src/stores/preferences.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export type UserPreferencesState = {
1818
cardsSettings: Record<string, CardSettingsType>
1919
firstSeenDate: number
2020
userCustomCards: SupportedCardType[]
21+
pauseTo: number
2122
}
2223

2324
type UserPreferencesStoreActions = {
@@ -32,6 +33,7 @@ type UserPreferencesStoreActions = {
3233
markOnboardingAsCompleted: (occupation: Omit<Occupation, 'icon'> | null) => void
3334
setUserCustomCards: (cards: SupportedCardType[]) => void
3435
updateCardOrder: (prevIndex: number, newIndex: number) => void
36+
setPauseTo: (value: number) => void
3537
}
3638

3739
export const useUserPreferences = create(
@@ -53,6 +55,7 @@ export const useUserPreferences = create(
5355
{ id: 3, name: 'producthunt', type: 'supported' },
5456
],
5557
userCustomCards: [],
58+
pauseTo: 0,
5659
setSearchEngine: (searchEngine: string) => set({ searchEngine: searchEngine }),
5760
setListingMode: (listingMode: ListingMode) => set({ listingMode: listingMode }),
5861
setTheme: (theme: Theme) => set({ theme: theme }),
@@ -76,17 +79,18 @@ export const useUserPreferences = create(
7679
onboardingResult: occupation,
7780
})),
7881
setUserCustomCards: (cards: SupportedCardType[]) => set({ userCustomCards: cards }),
79-
updateCardOrder: (prevIndex: number, newIndex: number) => set((state) => {
80-
81-
const newState = arrayMove(state.cards, prevIndex, newIndex).map((card, index) => {
82-
return {
83-
...card,
84-
id: index
85-
}
86-
})
82+
updateCardOrder: (prevIndex: number, newIndex: number) =>
83+
set((state) => {
84+
const newState = arrayMove(state.cards, prevIndex, newIndex).map((card, index) => {
85+
return {
86+
...card,
87+
id: index,
88+
}
89+
})
8790

88-
return { cards: newState}
89-
}),
91+
return { cards: newState }
92+
}),
93+
setPauseTo: (value) => set({ pauseTo: value }),
9094
}),
9195
{
9296
name: 'preferences_storage',

0 commit comments

Comments
 (0)