From 3738bb0b02291542fc69b977aafbbb143c458b3f Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 1 May 2021 19:02:07 +0900
Subject: [PATCH 01/91] Polishing Sidebar
---
.../organisms/settings/SettingsComponent.tsx | 48 ++++++++-----------
.../organisms/settings/TabButton.tsx | 12 ++---
2 files changed, 24 insertions(+), 36 deletions(-)
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index c2dfa58df9..ac34e0a9a8 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -11,16 +11,7 @@ import {
import { baseIconStyle } from '../../../lib/styled/styleFunctions'
import { useTranslation } from 'react-i18next'
import Icon from '../../atoms/IconMdi'
-import {
- mdiClose,
- mdiDomain,
- mdiAccountGroup,
- mdiProfessionalHexagon,
- mdiThemeLightDark,
- mdiFlash,
- mdiKey,
- mdiAccountCircleOutline,
-} from '@mdi/js'
+import { mdiClose, mdiDomain, mdiAccountCircleOutline } from '@mdi/js'
import {
StyledModals,
StyledModalsBackground,
@@ -43,6 +34,7 @@ import IntegrationsTab from './IntegrationsTab'
import PreferencesTab from './PreferencesTab'
import ApiTab from './ApiTab'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
+import IconMdi from '../../atoms/IconMdi'
const SettingsComponent = () => {
const { t } = useTranslation()
@@ -140,22 +132,26 @@ const SettingsComponent = () => {
- Account
+
+
+ Account
+
- Space
+
+
+ Space
+
{currentUserPermissions != null && (
<>
{
active={settingsTab === 'teamInfo'}
tab='teamInfo'
id='settings-teamInfoTab-btn'
- prependIcon={mdiDomain}
/>
>
)}
@@ -199,7 +191,6 @@ const SettingsComponent = () => {
active={settingsTab === 'teamUpgrade'}
tab='teamUpgrade'
id='settings-teamUpgradeTab-btn'
- prependIcon={mdiProfessionalHexagon}
/>
) : (
{
active={settingsTab === 'teamSubscription'}
tab='teamSubscription'
id='settings-teamBillingTab-btn'
- prependIcon={mdiProfessionalHexagon}
/>
)}
@@ -227,11 +217,10 @@ const SettingsComponent = () => {
const TabNav = styled.nav`
width: 250px;
- padding: 0;
+ padding: ${({ theme }) => theme.space.xsmall}px;
overflow: hidden auto;
margin-right: 0;
margin-bottom: 0;
- padding: ${({ theme }) => theme.space.xsmall}px 0;
hr {
height: 1px;
@@ -242,13 +231,16 @@ const TabNav = styled.nav`
`
const Subtitle = styled.div`
+ display: flex;
+ align-items: center;
margin: ${({ theme }) => theme.space.default}px
- ${({ theme }) => theme.space.default}px
- ${({ theme }) => theme.space.xsmall}px;
- color: ${({ theme }) => theme.baseTextColor};
- font-size: ${({ theme }) => theme.fontSizes.large}px;
- text-transform: uppercase;
- font-weight: 500;
+ ${({ theme }) => theme.space.small}px ${({ theme }) => theme.space.xsmall}px;
+ color: ${({ theme }) => theme.subtleTextColor};
+ font-size: ${({ theme }) => theme.fontSizes.default}px;
+
+ svg {
+ margin-right: ${({ theme }) => theme.space.xxsmall}px;
+ }
`
const TabContent = styled.div`
diff --git a/src/cloud/components/organisms/settings/TabButton.tsx b/src/cloud/components/organisms/settings/TabButton.tsx
index b31b148f43..914ed8a45d 100644
--- a/src/cloud/components/organisms/settings/TabButton.tsx
+++ b/src/cloud/components/organisms/settings/TabButton.tsx
@@ -2,17 +2,15 @@ import React, { useCallback } from 'react'
import styled from '../../../lib/styled'
import { SettingsTab, useSettings } from '../../../lib/stores/settings'
import cc from 'classcat'
-import IconMdi from '../../atoms/IconMdi'
interface TabButtonProps {
label: string
active: boolean
tab: SettingsTab
id?: string
- prependIcon: string
}
-const TabButton = ({ label, tab, active, id, prependIcon }: TabButtonProps) => {
+const TabButton = ({ label, tab, active, id }: TabButtonProps) => {
const { openSettingsTab } = useSettings()
const onClickHandler = useCallback(() => {
openSettingsTab(tab)
@@ -24,9 +22,6 @@ const TabButton = ({ label, tab, active, id, prependIcon }: TabButtonProps) => {
className={cc([active && 'active'])}
id={id}
>
-
-
-
{label}
)
@@ -39,10 +34,11 @@ const StyledButton = styled.button`
align-items: center;
width: 100%;
padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.small}px;
+ ${({ theme }) => theme.space.medium}px;
background-color: transparent;
border: none;
- color: ${({ theme }) => theme.subtleTextColor};
+ border-radius: 4px;
+ color: ${({ theme }) => theme.baseTextColor};
cursor: pointer;
.icon {
From c95a1bf533215228f67003343763621bc62a80eb Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 17:23:23 +0900
Subject: [PATCH 02/91] Created Settings Layout
---
.../components/molecules/SettingsLayout.tsx | 60 +++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 src/shared/components/molecules/SettingsLayout.tsx
diff --git a/src/shared/components/molecules/SettingsLayout.tsx b/src/shared/components/molecules/SettingsLayout.tsx
new file mode 100644
index 0000000000..9e5467e3eb
--- /dev/null
+++ b/src/shared/components/molecules/SettingsLayout.tsx
@@ -0,0 +1,60 @@
+import React from 'react'
+import styled from '../../lib/styled'
+import GlobalStyle from '../atoms/GlobalStyle'
+
+interface SettingsLayoutProps {
+ sidebar: React.ReactNode
+ pageBody: React.ReactNode
+}
+
+const SettingsLayout = ({ sidebar, pageBody }: SettingsLayoutProps) => (
+
+
+
{sidebar}
+
+
{pageBody}
+
+
+
+)
+
+const zIndexModals = 8001
+
+const Container = styled.div`
+ z-index: ${zIndexModals};
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: fixed;
+ left: 40px;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ background-color: ${({ theme }) => theme.colors.background.primary};
+ overflow: hidden;
+
+ .settings__wrapper {
+ z-index: ${zIndexModals + 2};
+ display: flex;
+ position: relative;
+ width: 100%;
+ height: 100%;
+ max-width: 100%;
+ max-height: 100%;
+ overflow: auto;
+ }
+
+ .settings__divider {
+ width: 1px;
+ height: 100%;
+ background-color: ${({ theme }) => theme.colors.border.main};
+ }
+
+ .settings__content {
+ flex: 1 1 100%;
+ min-width: 0;
+ overflow: auto;
+ }
+`
+
+export default SettingsLayout
From 6c351bd5e46d43a83be1e0e9ce1f2da2a3b263b9 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 17:43:42 +0900
Subject: [PATCH 03/91] Adding SettingsLayout
---
.../organisms/settings/SettingsComponent.tsx | 193 +++++++-----------
1 file changed, 76 insertions(+), 117 deletions(-)
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index ac34e0a9a8..eddb1a96f0 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -8,16 +8,8 @@ import {
useCapturingGlobalKeyDownHandler,
isSingleKeyEventOutsideOfInput,
} from '../../../lib/keyboard'
-import { baseIconStyle } from '../../../lib/styled/styleFunctions'
import { useTranslation } from 'react-i18next'
-import Icon from '../../atoms/IconMdi'
-import { mdiClose, mdiDomain, mdiAccountCircleOutline } from '@mdi/js'
-import {
- StyledModals,
- StyledModalsBackground,
- StyledModalsContainer,
- StyledSideNavModal,
-} from '../Modal/styled'
+import { mdiDomain, mdiAccountCircleOutline } from '@mdi/js'
import PersonalInfoTab from './PersonalInfoTab'
import { usePage } from '../../../lib/stores/pageStore'
import TeamInfoTab from './TeamInfoTab'
@@ -35,6 +27,7 @@ import PreferencesTab from './PreferencesTab'
import ApiTab from './ApiTab'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import IconMdi from '../../atoms/IconMdi'
+import SettingsLayout from '../../../../shared/components/molecules/SettingsLayout'
const SettingsComponent = () => {
const { t } = useTranslation()
@@ -108,13 +101,6 @@ const SettingsComponent = () => {
}
}, [settingsTab, currentUserPermissions])
- const backgroundClickHandler = useMemo(() => {
- return (event: MouseEvent) => {
- event.preventDefault()
- toggleClosed()
- }
- }, [toggleClosed])
-
useEffect(() => {
if (closed) {
return
@@ -127,91 +113,83 @@ const SettingsComponent = () => {
}
return (
-
-
-
-
-
-
-
- Account
-
-
-
-
-
- Space
-
- {currentUserPermissions != null && (
+
+
+
+ Account
+
+
+
+
+
+ Space
+
+ {currentUserPermissions != null && (
+ <>
+
+
+
+
+ >
+ )}
+ {team != null &&
+ currentUserPermissions != null &&
+ currentUserPermissions.role === 'admin' && (
<>
-
-
-
-
+ {subscription == null || subscription.status === 'trialing' ? (
+
+ ) : (
+
+ )}
+
>
)}
- {team != null &&
- currentUserPermissions != null &&
- currentUserPermissions.role === 'admin' && (
- <>
- {subscription == null ||
- subscription.status === 'trialing' ? (
-
- ) : (
-
- )}
-
- >
- )}
-
-
-
- {content}
-
-
-
-
-
+
+ }
+ pageBody={{content} }
+ >
)
}
@@ -249,23 +227,4 @@ const TabContent = styled.div`
position: relative;
`
-const CloseButton = styled.button`
- ${baseIconStyle}
- position: absolute;
- top: ${({ theme }) => theme.space.small}px;
- right: ${({ theme }) => theme.space.small}px;
- width: 40px;
- height: 40px;
- background-color: transparent;
- border: none;
- cursor: pointer;
- font-size: ${({ theme }) => theme.fontSizes.xxlarge}px;
-`
-
-const DividerBorder = styled.div`
- width: 1px;
- height: 100%;
- background-color: ${({ theme }) => theme.baseBorderColor};
-`
-
export default SettingsComponent
From 683fa94edcc0bc14a44f3ae038af6d6ae47faaeb Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 18:41:57 +0900
Subject: [PATCH 04/91] Removed GlobalStyle
---
src/shared/components/molecules/SettingsLayout.tsx | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/shared/components/molecules/SettingsLayout.tsx b/src/shared/components/molecules/SettingsLayout.tsx
index 9e5467e3eb..611de74710 100644
--- a/src/shared/components/molecules/SettingsLayout.tsx
+++ b/src/shared/components/molecules/SettingsLayout.tsx
@@ -1,6 +1,5 @@
import React from 'react'
import styled from '../../lib/styled'
-import GlobalStyle from '../atoms/GlobalStyle'
interface SettingsLayoutProps {
sidebar: React.ReactNode
@@ -14,7 +13,6 @@ const SettingsLayout = ({ sidebar, pageBody }: SettingsLayoutProps) => (
{pageBody}
-
)
From 2ef400410394176516a9156a5b8085be56f83f64 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:47:43 +0900
Subject: [PATCH 05/91] Removed Styled Components
---
.../organisms/settings/SettingsComponent.tsx | 79 ++++++-------------
1 file changed, 22 insertions(+), 57 deletions(-)
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index eddb1a96f0..4bf7fc6cbf 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -1,7 +1,6 @@
import React, { useMemo, useEffect } from 'react'
-import styled from '../../../lib/styled'
import { useSettings } from '../../../lib/stores/settings'
-import TabButton from './TabButton'
+import SettingSidenavItem from './SettingSidenavItem'
import {
preventKeyboardEventPropagation,
useUpDownNavigationListener,
@@ -26,8 +25,10 @@ import IntegrationsTab from './IntegrationsTab'
import PreferencesTab from './PreferencesTab'
import ApiTab from './ApiTab'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
-import IconMdi from '../../atoms/IconMdi'
-import SettingsLayout from '../../../../shared/components/molecules/SettingsLayout'
+import SettingsLayout from '../../../../shared/components/organisms/Settings/molecles/SettingsLayout'
+import SettingSidenavHeader from '../../../../shared/components/organisms/Settings/atoms/SettingSidenavHeader'
+import SettingSidenav from '../../../../shared/components/organisms/Settings/atoms/SettingSidenav'
+import SettingContent from '../../../../shared/components/organisms/Settings/atoms/SettingContent'
const SettingsComponent = () => {
const { t } = useTranslation()
@@ -115,48 +116,46 @@ const SettingsComponent = () => {
return (
-
-
- Account
-
-
+
+
-
-
-
- Space
-
+
{currentUserPermissions != null && (
<>
-
-
-
- {
currentUserPermissions.role === 'admin' && (
<>
{subscription == null || subscription.status === 'trialing' ? (
-
) : (
- {
>
)}
-
+
}
- pageBody={{content} }
+ content={{content} }
>
)
}
-const TabNav = styled.nav`
- width: 250px;
- padding: ${({ theme }) => theme.space.xsmall}px;
- overflow: hidden auto;
- margin-right: 0;
- margin-bottom: 0;
-
- hr {
- height: 1px;
- background-color: ${({ theme }) => theme.baseBorderColor};
- border: none;
- margin: ${({ theme }) => theme.space.small}px 0;
- }
-`
-
-const Subtitle = styled.div`
- display: flex;
- align-items: center;
- margin: ${({ theme }) => theme.space.default}px
- ${({ theme }) => theme.space.small}px ${({ theme }) => theme.space.xsmall}px;
- color: ${({ theme }) => theme.subtleTextColor};
- font-size: ${({ theme }) => theme.fontSizes.default}px;
-
- svg {
- margin-right: ${({ theme }) => theme.space.xxsmall}px;
- }
-`
-
-const TabContent = styled.div`
- flex: 1;
- overflow: hidden auto;
- position: relative;
-`
-
export default SettingsComponent
From 690b4fe87615f744a6391fd0bc8e115781caa486 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:48:16 +0900
Subject: [PATCH 06/91] Added SettingSidenavItem
---
.../organisms/settings/SettingSidenavItem.tsx | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 src/cloud/components/organisms/settings/SettingSidenavItem.tsx
diff --git a/src/cloud/components/organisms/settings/SettingSidenavItem.tsx b/src/cloud/components/organisms/settings/SettingSidenavItem.tsx
new file mode 100644
index 0000000000..e92845e45e
--- /dev/null
+++ b/src/cloud/components/organisms/settings/SettingSidenavItem.tsx
@@ -0,0 +1,35 @@
+import React, { useCallback } from 'react'
+import { SettingsTab, useSettings } from '../../../lib/stores/settings'
+import cc from 'classcat'
+import SettingTabButton from '../../../../shared/components/organisms/Settings/atoms/SettingTabButton'
+
+interface SettingSidenavItemProps {
+ label: string
+ active: boolean
+ tab: SettingsTab
+ id?: string
+}
+
+const SettingSidenavItem = ({
+ label,
+ tab,
+ active,
+ id,
+}: SettingSidenavItemProps) => {
+ const { openSettingsTab } = useSettings()
+ const onClickHandler = useCallback(() => {
+ openSettingsTab(tab)
+ }, [openSettingsTab, tab])
+
+ return (
+
+ {label}
+
+ )
+}
+
+export default SettingSidenavItem
From cd312fda616b25c5f4fb2d4d850f64f65a359b21 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:48:37 +0900
Subject: [PATCH 07/91] Removed TabButton
---
.../organisms/settings/TabButton.tsx | 67 -------------------
1 file changed, 67 deletions(-)
delete mode 100644 src/cloud/components/organisms/settings/TabButton.tsx
diff --git a/src/cloud/components/organisms/settings/TabButton.tsx b/src/cloud/components/organisms/settings/TabButton.tsx
deleted file mode 100644
index 914ed8a45d..0000000000
--- a/src/cloud/components/organisms/settings/TabButton.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React, { useCallback } from 'react'
-import styled from '../../../lib/styled'
-import { SettingsTab, useSettings } from '../../../lib/stores/settings'
-import cc from 'classcat'
-
-interface TabButtonProps {
- label: string
- active: boolean
- tab: SettingsTab
- id?: string
-}
-
-const TabButton = ({ label, tab, active, id }: TabButtonProps) => {
- const { openSettingsTab } = useSettings()
- const onClickHandler = useCallback(() => {
- openSettingsTab(tab)
- }, [openSettingsTab, tab])
-
- return (
-
- {label}
-
- )
-}
-
-export default TabButton
-
-const StyledButton = styled.button`
- display: flex;
- align-items: center;
- width: 100%;
- padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.medium}px;
- background-color: transparent;
- border: none;
- border-radius: 4px;
- color: ${({ theme }) => theme.baseTextColor};
- cursor: pointer;
-
- .icon {
- margin-left: ${({ theme }) => theme.space.small}px;
- margin-right: ${({ theme }) => theme.space.xsmall}px;
-
- svg {
- vertical-align: sub;
- }
- }
-
- .label {
- font-size: ${({ theme }) => theme.fontSizes.small}px;
- text-align: left;
- }
-
- &.active,
- &:hover,
- &:focus {
- color: ${({ theme }) => theme.emphasizedTextColor};
- }
-
- &.active {
- background-color: ${({ theme }) => theme.emphasizedBackgroundColor};
- }
-`
From 545df890f4fb5b312e1d6d15f7d70080c669dbdb Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:49:06 +0900
Subject: [PATCH 08/91] Moved SettingsLayout
---
.../Settings/molecles}/SettingsLayout.tsx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
rename src/shared/components/{molecules => organisms/Settings/molecles}/SettingsLayout.tsx (84%)
diff --git a/src/shared/components/molecules/SettingsLayout.tsx b/src/shared/components/organisms/Settings/molecles/SettingsLayout.tsx
similarity index 84%
rename from src/shared/components/molecules/SettingsLayout.tsx
rename to src/shared/components/organisms/Settings/molecles/SettingsLayout.tsx
index 611de74710..779cb7a8a9 100644
--- a/src/shared/components/molecules/SettingsLayout.tsx
+++ b/src/shared/components/organisms/Settings/molecles/SettingsLayout.tsx
@@ -1,17 +1,17 @@
import React from 'react'
-import styled from '../../lib/styled'
+import styled from '../../../../lib/styled'
interface SettingsLayoutProps {
sidebar: React.ReactNode
- pageBody: React.ReactNode
+ content: React.ReactNode
}
-const SettingsLayout = ({ sidebar, pageBody }: SettingsLayoutProps) => (
+const SettingsLayout = ({ sidebar, content }: SettingsLayoutProps) => (
{sidebar}
-
{pageBody}
+
{content}
)
From c6ce86e10936b620be31bcd25289bb8a7de6fe05 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:49:22 +0900
Subject: [PATCH 09/91] Removed Styled Component
---
src/components/PreferencesModal/TabButton.tsx | 38 ++-----------------
1 file changed, 3 insertions(+), 35 deletions(-)
diff --git a/src/components/PreferencesModal/TabButton.tsx b/src/components/PreferencesModal/TabButton.tsx
index cbaa4c6022..d107aa48c0 100644
--- a/src/components/PreferencesModal/TabButton.tsx
+++ b/src/components/PreferencesModal/TabButton.tsx
@@ -1,6 +1,6 @@
import React, { useCallback } from 'react'
-import styled from '../../lib/styled'
import cc from 'classcat'
+import SettingTabButton from '../../shared/components/organisms/Settings/atoms/SettingTabButton'
interface TabButtonProps {
label: string
@@ -9,46 +9,14 @@ interface TabButtonProps {
setTab: (tab: string) => void
}
-const StyledButton = styled.button`
- width: 100%;
- border-radius: 4px;
- height: 30px;
- background-color: ${({ theme }) => theme.navItemBackgroundColor};
- border: none;
- cursor: pointer;
- display: flex;
- align-items: center;
- margin-bottom: 5px;
-
- .label {
- flex: 1;
- color: ${({ theme }) => theme.navItemColor};
- text-align: left;
- padding-left: 15px;
- font-size: 14px;
- }
- &:hover {
- background-color: ${({ theme }) => theme.navItemHoverBackgroundColor};
- }
- &.active {
- color: ${({ theme }) => theme.textColor};
- background-color: ${({ theme }) => theme.navItemActiveBackgroundColor};
-
- .label {
- color: ${({ theme }) => theme.textColor};
- color: ${({ theme }) => theme.navItemActiveColor};
- }
- }
-`
-
const TabButton = ({ label, tab, setTab, active }: TabButtonProps) => {
const selectTab = useCallback(() => {
setTab(tab)
}, [tab, setTab])
return (
-
+
{label}
-
+
)
}
From 8810d4c6f7c1e32e51b2d37d6db03059e445cf30 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:49:59 +0900
Subject: [PATCH 10/91] Use Same Font Family Set
---
src/cloud/lib/styled/themes/shared.ts | 3 +--
src/components/GlobalStyle.tsx | 3 +--
src/lib/preview.ts | 3 +--
src/lib/styled/styleUtil.ts | 3 +--
4 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/src/cloud/lib/styled/themes/shared.ts b/src/cloud/lib/styled/themes/shared.ts
index 8d6f1f3ff6..c502ca2d88 100644
--- a/src/cloud/lib/styled/themes/shared.ts
+++ b/src/cloud/lib/styled/themes/shared.ts
@@ -1,8 +1,7 @@
import { InitialTheme } from './types'
export const sharedTheme: InitialTheme = {
- fontFamily: `-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Fira sans', Roboto, Helvetica,
- Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'`,
+ fontFamily: `Lato, -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif`,
fontSizes: {
xxxsmall: 8,
xxsmall: 10,
diff --git a/src/components/GlobalStyle.tsx b/src/components/GlobalStyle.tsx
index ddeb0bac82..33735c04ee 100644
--- a/src/components/GlobalStyle.tsx
+++ b/src/components/GlobalStyle.tsx
@@ -7,8 +7,7 @@ export default createGlobalStyle`
margin: 0;
${backgroundColor}
${textColor}
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Fira sans', Roboto, Helvetica,
- Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
+ font-family: Lato, -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
font-size: 15px;
font-weight: 400;
}
diff --git a/src/lib/preview.ts b/src/lib/preview.ts
index 4457e74e4d..07b13867df 100644
--- a/src/lib/preview.ts
+++ b/src/lib/preview.ts
@@ -7,8 +7,7 @@ export const defaultPreviewStyle = `
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
color: #24292e;
-font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
- sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
+font-family: Lato, -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
font-size: 15px;
line-height: 1.6;
word-wrap: break-word;
diff --git a/src/lib/styled/styleUtil.ts b/src/lib/styled/styleUtil.ts
index fc7d6073ec..c809485915 100644
--- a/src/lib/styled/styleUtil.ts
+++ b/src/lib/styled/styleUtil.ts
@@ -10,8 +10,7 @@ export const getGlobalCss = (theme: BaseTheme) => `
margin: 10px;
background-color: ${theme.backgroundColor};
color: ${theme.textColor};
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Fira sans', Roboto, Helvetica,
- Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
+ font-family: Lato, -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
font-size: 15px;
font-weight: 400;
}
From 7bb6ac8ffd32b98c311d4c414f26b1c3dd76ac2b Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:50:17 +0900
Subject: [PATCH 11/91] Added SettingContent
---
.../organisms/Settings/atoms/SettingContent.tsx | 9 +++++++++
1 file changed, 9 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingContent.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingContent.tsx b/src/shared/components/organisms/Settings/atoms/SettingContent.tsx
new file mode 100644
index 0000000000..c8be1f82b4
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingContent.tsx
@@ -0,0 +1,9 @@
+import styled from '../../../../../lib/styled'
+
+const SettingContent = styled.div`
+ flex: 1;
+ overflow: hidden auto;
+ position: relative;
+`
+
+export default SettingContent
From f77f99cfef20d66c50d4c30b60090e47ec7227c3 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:50:27 +0900
Subject: [PATCH 12/91] Added SettingSidenav
---
.../organisms/Settings/atoms/SettingSidenav.tsx | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingSidenav.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingSidenav.tsx b/src/shared/components/organisms/Settings/atoms/SettingSidenav.tsx
new file mode 100644
index 0000000000..2105ef3f4b
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingSidenav.tsx
@@ -0,0 +1,11 @@
+import styled from '../../../../lib/styled'
+
+const SettingSidenav = styled.nav`
+ width: 250px;
+ margin-bottom: 0;
+ margin-right: 0;
+ padding: ${({ theme }) => theme.sizes.spaces.sm}px;
+ overflow: hidden auto;
+`
+
+export default SettingSidenav
From 41986660d26aeaeb75b81dedd223f731017b6867 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:50:39 +0900
Subject: [PATCH 13/91] Added SettingSidenavHeader
---
.../Settings/atoms/SettingSidenavHeader.tsx | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingSidenavHeader.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingSidenavHeader.tsx b/src/shared/components/organisms/Settings/atoms/SettingSidenavHeader.tsx
new file mode 100644
index 0000000000..363a8fdc3d
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingSidenavHeader.tsx
@@ -0,0 +1,35 @@
+import React from 'react'
+import styled from '../../../../lib/styled'
+import Icon, { IconSize } from '../../../atoms/Icon'
+
+interface SettingSidenavHeaderProps {
+ path: string
+ text: string
+ size: IconSize
+}
+
+const SettingSidenavHeader = ({
+ path,
+ text,
+ size,
+}: SettingSidenavHeaderProps) => (
+
+
+ {text}
+
+)
+
+const Container = styled.div`
+ display: flex;
+ align-items: center;
+ margin: ${({ theme }) => theme.sizes.spaces.md}px 0
+ ${({ theme }) => theme.sizes.spaces.sm}px;
+ color: ${({ theme }) => theme.colors.text.subtle};
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+
+ svg {
+ margin-right: ${({ theme }) => theme.sizes.spaces.xsm}px;
+ }
+`
+
+export default SettingSidenavHeader
From 2b18f6e7d67c5e4487cf1b7a11a6779278daddc1 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 19:50:50 +0900
Subject: [PATCH 14/91] Added SettingTabButton
---
.../Settings/atoms/SettingTabButton.tsx | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
new file mode 100644
index 0000000000..e006ff8b4b
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
@@ -0,0 +1,28 @@
+import styled from '../../../../lib/styled'
+
+const SettingTabButton = styled.button`
+ display: flex;
+ align-items: center;
+ width: 100%;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px;
+ padding: ${({ theme }) => theme.sizes.spaces.xsm}px
+ ${({ theme }) => theme.sizes.spaces.md}px;
+ background-color: transparent;
+ border: none;
+ border-radius: 4px;
+ color: ${({ theme }) => theme.colors.text.primary};
+ cursor: pointer;
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+ text-align: left;
+
+ &:hover,
+ &:focus {
+ background-color: ${({ theme }) => theme.colors.background.tertiary};
+ }
+
+ &.active {
+ background-color: ${({ theme }) => theme.colors.background.quaternary};
+ }
+`
+
+export default SettingTabButton
From 7dee8090dbaee2ad00938eab71137f5ee1e5c125 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 20:04:25 +0900
Subject: [PATCH 15/91] Changed the border-radius
---
.../components/organisms/Settings/atoms/SettingTabButton.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
index e006ff8b4b..012406df87 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
@@ -9,7 +9,7 @@ const SettingTabButton = styled.button`
${({ theme }) => theme.sizes.spaces.md}px;
background-color: transparent;
border: none;
- border-radius: 4px;
+ border-radius: 2px;
color: ${({ theme }) => theme.colors.text.primary};
cursor: pointer;
font-size: ${({ theme }) => theme.sizes.fonts.df}px;
From 86b9c7d724351b66a0f15356b8a13d174810a520 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 3 May 2021 20:10:19 +0900
Subject: [PATCH 16/91] Updated Font Family
---
src/cloud/components/atoms/MarkdownView/styles.ts | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/cloud/components/atoms/MarkdownView/styles.ts b/src/cloud/components/atoms/MarkdownView/styles.ts
index 8adebf93fc..3bc089d315 100644
--- a/src/cloud/components/atoms/MarkdownView/styles.ts
+++ b/src/cloud/components/atoms/MarkdownView/styles.ts
@@ -114,8 +114,7 @@ export const defaultPreviewStyle = ({ theme }: StyledProps) => `
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
line-height: 1.6;
-font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
- sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
+font-family: Lato, -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
font-size: 15px;
line-height: 1.6;
word-wrap: break-word;
From 95f9bc857593f0ff28be5c032dcecab6d8849833 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 8 May 2021 15:03:42 +0900
Subject: [PATCH 17/91] SettingSidenavItem -> SettingTabButton
---
.../organisms/settings/SettingSidenavItem.tsx | 35 -------------------
.../organisms/settings/SettingsComponent.tsx | 27 +++++++++-----
.../Settings/atoms/SettingTabButton.tsx | 32 ++++++++++++++++-
3 files changed, 49 insertions(+), 45 deletions(-)
delete mode 100644 src/cloud/components/organisms/settings/SettingSidenavItem.tsx
diff --git a/src/cloud/components/organisms/settings/SettingSidenavItem.tsx b/src/cloud/components/organisms/settings/SettingSidenavItem.tsx
deleted file mode 100644
index e92845e45e..0000000000
--- a/src/cloud/components/organisms/settings/SettingSidenavItem.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import React, { useCallback } from 'react'
-import { SettingsTab, useSettings } from '../../../lib/stores/settings'
-import cc from 'classcat'
-import SettingTabButton from '../../../../shared/components/organisms/Settings/atoms/SettingTabButton'
-
-interface SettingSidenavItemProps {
- label: string
- active: boolean
- tab: SettingsTab
- id?: string
-}
-
-const SettingSidenavItem = ({
- label,
- tab,
- active,
- id,
-}: SettingSidenavItemProps) => {
- const { openSettingsTab } = useSettings()
- const onClickHandler = useCallback(() => {
- openSettingsTab(tab)
- }, [openSettingsTab, tab])
-
- return (
-
- {label}
-
- )
-}
-
-export default SettingSidenavItem
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index 4bf7fc6cbf..fdfa22046e 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -1,6 +1,5 @@
import React, { useMemo, useEffect } from 'react'
import { useSettings } from '../../../lib/stores/settings'
-import SettingSidenavItem from './SettingSidenavItem'
import {
preventKeyboardEventPropagation,
useUpDownNavigationListener,
@@ -29,12 +28,14 @@ import SettingsLayout from '../../../../shared/components/organisms/Settings/mol
import SettingSidenavHeader from '../../../../shared/components/organisms/Settings/atoms/SettingSidenavHeader'
import SettingSidenav from '../../../../shared/components/organisms/Settings/atoms/SettingSidenav'
import SettingContent from '../../../../shared/components/organisms/Settings/atoms/SettingContent'
+import SettingTabButton from '../../../../shared/components/organisms/Settings/atoms/SettingTabButton'
const SettingsComponent = () => {
const { t } = useTranslation()
const { closed, toggleClosed, settingsTab } = useSettings()
const contentSideRef = React.createRef()
const menuRef = React.createRef()
+ const { openSettingsTab } = useSettings()
const { team, subscription, currentUserPermissions } = usePage<
PageStoreWithTeam
>()
@@ -122,44 +123,50 @@ const SettingsComponent = () => {
text={'Account'}
size={16}
/>
- openSettingsTab('personalInfo')}
/>
- openSettingsTab('preferences')}
/>
{currentUserPermissions != null && (
<>
- openSettingsTab('teamInfo')}
/>
- openSettingsTab('teamMembers')}
/>
- openSettingsTab('integrations')}
/>
- openSettingsTab('api')}
/>
>
)}
@@ -168,18 +175,20 @@ const SettingsComponent = () => {
currentUserPermissions.role === 'admin' && (
<>
{subscription == null || subscription.status === 'trialing' ? (
- openSettingsTab('teamUpgrade')}
/>
) : (
- openSettingsTab('teamSubscription')}
/>
)}
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
index 012406df87..b9eafcdbbf 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
@@ -1,6 +1,36 @@
+import React, { MouseEventHandler } from 'react'
+import cc from 'classcat'
import styled from '../../../../lib/styled'
+import { SettingsTab } from '../../../../../cloud/lib/stores/settings'
-const SettingTabButton = styled.button`
+interface SettingTabButtonProps {
+ label: string
+ active: boolean
+ tab: SettingsTab
+ id?: string
+ onClick?: MouseEventHandler
+}
+
+const SettingTabButton = ({
+ label,
+ tab,
+ active,
+ id,
+ onClick,
+}: SettingTabButtonProps) => {
+ return (
+
+ {label}
+
+ )
+}
+
+const Container = styled.button`
display: flex;
align-items: center;
width: 100%;
From 214d14e558e4e998521b8b94d113911f3ad8475d Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 8 May 2021 15:13:07 +0900
Subject: [PATCH 18/91] SettingsLayout -> Settings
---
.../components/organisms/settings/SettingsComponent.tsx | 6 +++---
.../Settings/{molecles/SettingsLayout.tsx => index.tsx} | 8 ++++----
2 files changed, 7 insertions(+), 7 deletions(-)
rename src/shared/components/organisms/Settings/{molecles/SettingsLayout.tsx => index.tsx} (85%)
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index fdfa22046e..6a1e32a645 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -24,7 +24,7 @@ import IntegrationsTab from './IntegrationsTab'
import PreferencesTab from './PreferencesTab'
import ApiTab from './ApiTab'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
-import SettingsLayout from '../../../../shared/components/organisms/Settings/molecles/SettingsLayout'
+import Settings from '../../../../shared/components/organisms/Settings'
import SettingSidenavHeader from '../../../../shared/components/organisms/Settings/atoms/SettingSidenavHeader'
import SettingSidenav from '../../../../shared/components/organisms/Settings/atoms/SettingSidenav'
import SettingContent from '../../../../shared/components/organisms/Settings/atoms/SettingContent'
@@ -115,7 +115,7 @@ const SettingsComponent = () => {
}
return (
-
{
}
content={{content} }
- >
+ >
)
}
diff --git a/src/shared/components/organisms/Settings/molecles/SettingsLayout.tsx b/src/shared/components/organisms/Settings/index.tsx
similarity index 85%
rename from src/shared/components/organisms/Settings/molecles/SettingsLayout.tsx
rename to src/shared/components/organisms/Settings/index.tsx
index 779cb7a8a9..cb44067480 100644
--- a/src/shared/components/organisms/Settings/molecles/SettingsLayout.tsx
+++ b/src/shared/components/organisms/Settings/index.tsx
@@ -1,12 +1,12 @@
import React from 'react'
-import styled from '../../../../lib/styled'
+import styled from '../../../lib/styled'
-interface SettingsLayoutProps {
+interface SettingsProps {
sidebar: React.ReactNode
content: React.ReactNode
}
-const SettingsLayout = ({ sidebar, content }: SettingsLayoutProps) => (
+const Settings = ({ sidebar, content }: SettingsProps) => (
{sidebar}
@@ -55,4 +55,4 @@ const Container = styled.div`
}
`
-export default SettingsLayout
+export default Settings
From 66a59eaeb71c2a9cb4623ae955d3683209a3ac10 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 8 May 2021 15:36:33 +0900
Subject: [PATCH 19/91] Removed TabButton
---
.../PreferencesModal/PreferencesModal.tsx | 42 ++++++++++---------
src/components/PreferencesModal/TabButton.tsx | 23 ----------
.../Settings/atoms/SettingTabButton.tsx | 3 +-
3 files changed, 24 insertions(+), 44 deletions(-)
delete mode 100644 src/components/PreferencesModal/TabButton.tsx
diff --git a/src/components/PreferencesModal/PreferencesModal.tsx b/src/components/PreferencesModal/PreferencesModal.tsx
index 4cb37e1a98..1856198f85 100644
--- a/src/components/PreferencesModal/PreferencesModal.tsx
+++ b/src/components/PreferencesModal/PreferencesModal.tsx
@@ -1,7 +1,6 @@
import React, { useMemo, useCallback } from 'react'
import styled from '../../lib/styled'
import { usePreferences } from '../../lib/preferences'
-import TabButton from './TabButton'
import { useGlobalKeyDownHandler } from '../../lib/keyboard'
import GeneralTab from './GeneralTab'
import EditorTab from './EditorTab'
@@ -24,6 +23,7 @@ import StorageTab from './StorageTab'
import MigrationPage from './MigrationTab'
import { useMigrations } from '../../lib/migrate/store'
import KeymapTab from './KeymapTab'
+import SettingTabButton from '../../shared/components/organisms/Settings/atoms/SettingTabButton'
const FullScreenContainer = styled.div`
z-index: 7000;
@@ -177,43 +177,47 @@ const PreferencesModal = () => {
- openTab('about')}
/>
- openTab('keymap')}
/>
- openTab('general')}
/>
{currentStorage != null && (
-
+ openTab(
+ get(currentStorage.id) != null ? 'migration' : 'storage'
+ )
+ }
/>
)}
- openTab('editor')}
/>
- openTab('markdown')}
/>
{content}
diff --git a/src/components/PreferencesModal/TabButton.tsx b/src/components/PreferencesModal/TabButton.tsx
deleted file mode 100644
index d107aa48c0..0000000000
--- a/src/components/PreferencesModal/TabButton.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import React, { useCallback } from 'react'
-import cc from 'classcat'
-import SettingTabButton from '../../shared/components/organisms/Settings/atoms/SettingTabButton'
-
-interface TabButtonProps {
- label: string
- tab: string
- active: boolean
- setTab: (tab: string) => void
-}
-
-const TabButton = ({ label, tab, setTab, active }: TabButtonProps) => {
- const selectTab = useCallback(() => {
- setTab(tab)
- }, [tab, setTab])
- return (
-
- {label}
-
- )
-}
-
-export default TabButton
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
index b9eafcdbbf..167c0a142d 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabButton.tsx
@@ -1,12 +1,11 @@
import React, { MouseEventHandler } from 'react'
import cc from 'classcat'
import styled from '../../../../lib/styled'
-import { SettingsTab } from '../../../../../cloud/lib/stores/settings'
interface SettingTabButtonProps {
label: string
active: boolean
- tab: SettingsTab
+ tab: string
id?: string
onClick?: MouseEventHandler
}
From d91441efd1c3b7082080ba6af6be79cdd0a2199d Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 8 May 2021 18:01:01 +0900
Subject: [PATCH 20/91] Created SettingTeamSubLimit
---
.../organisms/settings/TeamSubLimit.tsx | 85 ++-----------------
.../Settings/atoms/SettingTeamSubLimit.tsx | 69 +++++++++++++++
2 files changed, 75 insertions(+), 79 deletions(-)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingTeamSubLimit.tsx
diff --git a/src/cloud/components/organisms/settings/TeamSubLimit.tsx b/src/cloud/components/organisms/settings/TeamSubLimit.tsx
index 6f87c066cd..7e0a8b288a 100644
--- a/src/cloud/components/organisms/settings/TeamSubLimit.tsx
+++ b/src/cloud/components/organisms/settings/TeamSubLimit.tsx
@@ -1,8 +1,8 @@
import React from 'react'
-import styled from '../../../lib/styled'
-import { usePage } from '../../../lib/stores/pageStore'
import cc from 'classcat'
+import { usePage } from '../../../lib/stores/pageStore'
import { useSettings } from '../../../lib/stores/settings'
+import SettingTeamSubLimit from '../../../../shared/components/organisms/Settings/atoms/SettingTeamSubLimit'
const TeamSubLimit = () => {
const { subscription, team, currentSubInfo } = usePage()
@@ -18,7 +18,7 @@ const TeamSubLimit = () => {
if (currentSubInfo.trialing) {
return (
-
+
{
You can upgrade at anytime during your trial.
-
+
)
}
return (
-
+
{
)}
-
+
)
}
-const StyledSidebarTeamSubLimit = styled.div`
- width: 100%;
- color: ${({ theme }) => theme.baseTextColor};
- font-size: ${({ theme }) => theme.fontSizes.xsmall}px;
-
- p {
- color: ${({ theme }) => theme.subtleTextColor};
- margin: 10px 0px;
- }
-
- .note-limit {
- font-size: ${({ theme }) => theme.fontSizes.small}px;
- }
-
- .progress-sm {
- display: block;
- width: 100%;
- overflow: hidden;
- height: 3px;
- font-size: 0.75rem;
- background-color: ${({ theme }) => theme.subtleBackgroundColor};
- border-radius: 0.25rem;
- text-align: center;
- position: relative;
- }
-
- .progress-bar {
- background-color: ${({ theme }) => theme.primaryBackgroundColor};
- max-width: 100%;
- flex-direction: column;
- justify-content: center;
- text-align: center;
- white-space: nowrap;
- transition: width 0.6s ease;
- height: 3px;
-
- &.over-limit {
- background-color: ${({ theme }) => theme.dangerBackgroundColor};
- }
- }
-
- .upgrade-link {
- &:hover,
- &:focus {
- background-color: ${({ theme }) => theme.subtleBackgroundColor};
- }
- cursor: pointer;
- display: block;
- margin: 10px 0 5px 0;
- padding: 15px;
- text-decoration: none;
- }
-
- h6 {
- font-size: ${({ theme }) => theme.fontSizes.default}px;
- margin: 0;
- color: ${({ theme }) => theme.primaryTextColor};
- }
-
- .progress-label {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- margin: auto;
- }
-
- .text-danger {
- color: ${({ theme }) => theme.dangerTextColor};
- }
-`
-
export default TeamSubLimit
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTeamSubLimit.tsx b/src/shared/components/organisms/Settings/atoms/SettingTeamSubLimit.tsx
new file mode 100644
index 0000000000..723df18239
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingTeamSubLimit.tsx
@@ -0,0 +1,69 @@
+import styled from '../../../../lib/styled'
+
+const SettingTeamSubLimit = styled.nav`
+ width: 100%;
+ margin-top: ${({ theme }) => theme.sizes.spaces.l}px;
+
+ h6 {
+ margin: 0;
+ color: ${({ theme }) => theme.colors.variants.primary.base};
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+ }
+
+ p {
+ margin: ${({ theme }) => theme.sizes.spaces.sm}px 0;
+ color: ${({ theme }) => theme.colors.text.subtle};
+ font-size: ${({ theme }) => theme.sizes.fonts.sm}px;
+ }
+
+ .upgrade-link {
+ display: block;
+ margin-top: ${({ theme }) => theme.sizes.spaces.sm}px;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px;
+ padding: ${({ theme }) => theme.sizes.spaces.df}px;
+ cursor: pointer;
+ text-decoration: none;
+
+ &:hover,
+ &:focus {
+ background-color: ${({ theme }) => theme.colors.background.tertiary};
+ }
+ }
+
+ .note-limit {
+ font-size: ${({ theme }) => theme.sizes.fonts.sm}px;
+ }
+
+ .progress-sm {
+ display: block;
+ position: relative;
+ width: 100%;
+ height: 3px;
+ background-color: ${({ theme }) => theme.colors.background.quaternary};
+ border-radius: 0.25rem;
+ font-size: 0.75rem;
+ overflow: hidden;
+ text-align: center;
+ }
+
+ .progress-bar {
+ flex-direction: column;
+ justify-content: center;
+ height: 3px;
+ max-width: 100%;
+ background-color: ${({ theme }) => theme.colors.background.primary};
+ text-align: center;
+ white-space: nowrap;
+ transition: width 0.6s ease;
+
+ &.over-limit {
+ background-color: ${({ theme }) => theme.colors.variants.danger.base};
+ }
+ }
+
+ .text-danger {
+ color: ${({ theme }) => theme.colors.variants.danger.base};
+ }
+`
+
+export default SettingTeamSubLimit
From 175f955d35c9c3ba5afcbc7c7f5947bc4c280cdc Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 8 May 2021 22:11:05 +0900
Subject: [PATCH 21/91] SettingContent -> SettingMain
---
.../Settings/atoms/{SettingContent.tsx => SettingMain.tsx} | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
rename src/shared/components/organisms/Settings/atoms/{SettingContent.tsx => SettingMain.tsx} (62%)
diff --git a/src/shared/components/organisms/Settings/atoms/SettingContent.tsx b/src/shared/components/organisms/Settings/atoms/SettingMain.tsx
similarity index 62%
rename from src/shared/components/organisms/Settings/atoms/SettingContent.tsx
rename to src/shared/components/organisms/Settings/atoms/SettingMain.tsx
index c8be1f82b4..fd8ae7695d 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingContent.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingMain.tsx
@@ -1,9 +1,9 @@
import styled from '../../../../../lib/styled'
-const SettingContent = styled.div`
+const SettingMain = styled.div`
flex: 1;
- overflow: hidden auto;
position: relative;
+ overflow: hidden auto;
`
-export default SettingContent
+export default SettingMain
From f2a778c671855e1277456f85b9c2fa0d00b59765 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 8 May 2021 22:11:20 +0900
Subject: [PATCH 22/91] Added SettingTabContent
---
.../Settings/atoms/SettingTabContent.tsx | 53 +++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
new file mode 100644
index 0000000000..14d0954018
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
@@ -0,0 +1,53 @@
+import React from 'react'
+import styled from '../../../../lib/styled'
+
+interface SettingTabContentProps {
+ header?: React.ReactNode
+ body: React.ReactNode
+}
+
+const SettingTabContent = ({ header, body }: SettingTabContentProps) => (
+
+
+
+)
+
+const Container = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+
+ .tab-content__scrollable {
+ flex: 1 1 auto;
+ width: 100%;
+ padding: ${({ theme }) => theme.sizes.spaces.xl}px
+ ${({ theme }) => theme.sizes.spaces.md}px;
+ overflow: hidden auto;
+ }
+
+ .tab-content__container {
+ max-width: 700px;
+ margin: 0 auto;
+ }
+
+ .tab-content__header {
+ margin-top: 0;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px;
+ font-size: ${({ theme }) => theme.sizes.fonts.xl}px;
+ font-weight: 500;
+ }
+
+ .tab-content__body {
+ section {
+ padding: ${({ theme }) => theme.sizes.spaces.xsm}px 0;
+ }
+ }
+`
+
+export default SettingTabContent
From a3478ad97bb3472b4d98907c894c8406a9402d34 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 8 May 2021 22:23:28 +0900
Subject: [PATCH 23/91] Apply SettingTabContent
---
.../components/organisms/settings/ApiTab.tsx | 34 ++---
.../organisms/settings/AppFeedbackTab.tsx | 20 ++-
.../components/organisms/settings/InfoTab.tsx | 28 ++--
.../organisms/settings/IntegrationsTab.tsx | 37 ++---
.../organisms/settings/MembersTab.tsx | 68 ++++------
.../organisms/settings/PersonalInfoTab.tsx | 39 +++---
.../organisms/settings/PreferencesTab.tsx | 16 +--
.../organisms/settings/SubscriptionTab.tsx | 128 ++++++++----------
.../organisms/settings/TeamInfoTab.tsx | 39 ++----
.../organisms/settings/UpgradeTab.tsx | 103 +++++++-------
10 files changed, 219 insertions(+), 293 deletions(-)
diff --git a/src/cloud/components/organisms/settings/ApiTab.tsx b/src/cloud/components/organisms/settings/ApiTab.tsx
index d363989741..1222678e48 100644
--- a/src/cloud/components/organisms/settings/ApiTab.tsx
+++ b/src/cloud/components/organisms/settings/ApiTab.tsx
@@ -1,15 +1,6 @@
import React, { useCallback, useMemo, useState } from 'react'
import styled from '../../../lib/styled'
-import {
- Section,
- TabHeader,
- Column,
- Container,
- Scrollable,
- SectionSubtleText,
- SectionHeader2,
- PrimaryAnchor,
-} from './styled'
+import { SectionSubtleText, SectionHeader2, PrimaryAnchor } from './styled'
import CustomButton from '../../atoms/buttons/CustomButton'
import Spinner from '../../atoms/CustomSpinner'
import { useApiTokens, withApiTokens } from '../../../lib/stores/apiTokens'
@@ -19,6 +10,7 @@ import { usePage } from '../../../lib/stores/pageStore'
import Flexbox from '../../atoms/Flexbox'
import Icon from '../../atoms/IconMdi'
import { mdiOpenInNew } from '@mdi/js'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const ApiTab = () => {
const { team } = usePage()
@@ -42,17 +34,17 @@ const ApiTab = () => {
}, [apiTokenState, team])
return (
-
-
-
-
- API
+
+
These tokens are available only to{' '}
{team != null ? team.name : 'your team'}.
-
-
+
@@ -103,10 +95,10 @@ const ApiTab = () => {
})}
)}
-
-
-
-
+
+ >
+ }
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/AppFeedbackTab.tsx b/src/cloud/components/organisms/settings/AppFeedbackTab.tsx
index a0665295df..2b40c42d1c 100644
--- a/src/cloud/components/organisms/settings/AppFeedbackTab.tsx
+++ b/src/cloud/components/organisms/settings/AppFeedbackTab.tsx
@@ -1,22 +1,20 @@
import React from 'react'
-import { Column, Container, Scrollable, Section, TabHeader } from './styled'
import { useTranslation } from 'react-i18next'
import AppFeedbackForm from '../../molecules/AppFeedbackForm'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const AppFeedbackTab = () => {
const { t } = useTranslation()
return (
-
-
-
- {t('settings.appFeedback')}
-
-
-
-
+
+
+
+ }
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/InfoTab.tsx b/src/cloud/components/organisms/settings/InfoTab.tsx
index 9a91664163..d501425ba3 100644
--- a/src/cloud/components/organisms/settings/InfoTab.tsx
+++ b/src/cloud/components/organisms/settings/InfoTab.tsx
@@ -1,13 +1,8 @@
import React, { useCallback, useState, useMemo } from 'react'
import {
- Section,
- TabHeader,
SectionLabel,
SectionInput,
SectionProfilePic,
- Column,
- Container,
- Scrollable,
SectionFlexLeft,
SectionSeparator,
SectionDescription,
@@ -27,6 +22,7 @@ import {
dangerButtonStyle,
} from '../../../lib/styled/styleFunctions'
import { useToast } from '../../../../shared/lib/stores/toast'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const InfoTab = () => {
const {
@@ -87,11 +83,11 @@ const InfoTab = () => {
}, [currentUser])
return (
-
-
-
- {t('settings.info')}
-
+
+
{currentUser != null && (
<>
Display Name
@@ -123,9 +119,9 @@ const InfoTab = () => {
{t('general.cancel')}
-
+
-
+
{t('settings.account.delete')}
@@ -142,10 +138,10 @@ const InfoTab = () => {
{t('general.delete')}
-
-
-
-
+
+ >
+ }
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/IntegrationsTab.tsx b/src/cloud/components/organisms/settings/IntegrationsTab.tsx
index b357b33e4e..cb0df7b9b2 100644
--- a/src/cloud/components/organisms/settings/IntegrationsTab.tsx
+++ b/src/cloud/components/organisms/settings/IntegrationsTab.tsx
@@ -1,14 +1,6 @@
import React, { useCallback, useMemo } from 'react'
import styled from '../../../lib/styled'
-import {
- Section,
- TabHeader,
- Column,
- Container,
- Scrollable,
- SectionSubtleText,
- SectionHeader2,
-} from './styled'
+import { SectionSubtleText, SectionHeader2 } from './styled'
import CustomButton from '../../atoms/buttons/CustomButton'
import ServiceConnect from '../../atoms/ServiceConnect'
import Spinner from '../../atoms/CustomSpinner'
@@ -25,6 +17,7 @@ import Button from '../../atoms/Button'
import { openNew } from '../../../lib/utils/platform'
import { usePage } from '../../../lib/stores/pageStore'
import { useModal } from '../../../../shared/lib/stores/modal'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const IntegrationsTab = () => {
const { openModal } = useModal()
@@ -48,11 +41,11 @@ const IntegrationsTab = () => {
}, [])
return (
-
-
-
-
- Integrations
+
+
Connect 3rd party content to your Boost Note for Teams documents.
@@ -77,8 +70,8 @@ const IntegrationsTab = () => {
-
-
+
Popular Integrations
@@ -509,8 +502,8 @@ const IntegrationsTab = () => {
-
-
+
External Entity
@@ -592,10 +585,10 @@ const IntegrationsTab = () => {
-
-
-
-
+
+ >
+ }
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/MembersTab.tsx b/src/cloud/components/organisms/settings/MembersTab.tsx
index 84dbe48a5c..b2229b2264 100644
--- a/src/cloud/components/organisms/settings/MembersTab.tsx
+++ b/src/cloud/components/organisms/settings/MembersTab.tsx
@@ -1,10 +1,5 @@
import React, { useCallback, useState, useEffect, useRef } from 'react'
import {
- Section,
- Column,
- Container,
- Scrollable,
- TabHeader,
SectionHeader2,
StyledMembername,
SectionSelect,
@@ -53,6 +48,7 @@ import { getDocTitle } from '../../../lib/utils/patterns'
import SettingsTeamForm from '../../molecules/SettingsTeamForm'
import { guestsPerMember } from '../../../lib/subscription'
import { useToast } from '../../../../shared/lib/stores/toast'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const MembersTab = () => {
const { t } = useTranslation()
@@ -402,16 +398,14 @@ const MembersTab = () => {
if (currentUserPermissions == null || team == null) {
return (
-
-
-
- {t('settings.teamMembers')}
-
- You don't own any permissions.
-
-
-
-
+
+ You don't own any permissions.
+
+ }
+ >
)
}
@@ -419,24 +413,22 @@ const MembersTab = () => {
if (team.personal && showTeamPersonalForm) {
return (
-
-
-
- setShowTeamPersonalForm(false)}
- teamConversion={true}
- />
-
-
-
+ setShowTeamPersonalForm(false)}
+ teamConversion={true}
+ />
+ }
+ >
)
}
return (
-
-
-
+
{
{tab === 'member' ? (
team.personal ? (
-
+
Current Members
{fetching.has('userEmails') && (
@@ -493,7 +485,7 @@ const MembersTab = () => {
-
+
) : (
<>
{currentUserIsAdmin && (
@@ -502,7 +494,7 @@ const MembersTab = () => {
/>
)}
-
+
Current Members
{fetching.has('userEmails') && (
@@ -600,7 +592,7 @@ const MembersTab = () => {
})}
- {' '}
+ {' '}
>
)
) : (
@@ -633,7 +625,7 @@ const MembersTab = () => {
>
) : (
-
+
Current Guests
{fetching.has('guestEmails') && (
@@ -694,13 +686,13 @@ const MembersTab = () => {
))}
-
+
)}
>
)}
-
-
-
+ >
+ }
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
index 785d4f0bc7..24384208d2 100644
--- a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
@@ -1,18 +1,14 @@
import React, { useCallback, useState, useMemo } from 'react'
import {
- Section,
- TabHeader,
SectionLabel,
SectionInput,
SectionProfilePic,
- Column,
- Container,
- Scrollable,
SectionFlexLeft,
SectionSeparator,
SectionDescription,
SectionSelect,
SectionHeader3,
+ SectionHeader2,
} from './styled'
import { useTranslation } from 'react-i18next'
import { useGlobalData } from '../../../lib/stores/globalData'
@@ -27,6 +23,7 @@ import { SelectChangeEventHandler } from '../../../lib/utils/events'
import { UserEmailNotificationType } from '../../../interfaces/db/userSettings'
import { saveUserSettings } from '../../../api/users/settings'
import { useToast } from '../../../../shared/lib/stores/toast'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const PersonalInfoTab = () => {
const {
@@ -121,13 +118,11 @@ const PersonalInfoTab = () => {
)
return (
-
-
-
-
- {t('settings.personalInfo')}
-
-
+
+
{currentUser != null && (
<>
Display Name
@@ -145,10 +140,8 @@ const PersonalInfoTab = () => {
{currentUser != null && (
<>
-
- {t('settings.notifications')}
-
-
+ {t('settings.notifications')}
+
{t('settings.notificationsFrequency')}
@@ -176,7 +169,7 @@ const PersonalInfoTab = () => {
Never
-
+
>
)}
@@ -197,9 +190,9 @@ const PersonalInfoTab = () => {
{t('general.cancel')}
-
+
-
+
{t('settings.account.delete')}
@@ -210,10 +203,10 @@ const PersonalInfoTab = () => {
{t('general.delete')}
-
-
-
-
+
+ >
+ }
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/PreferencesTab.tsx b/src/cloud/components/organisms/settings/PreferencesTab.tsx
index baeba846fd..5d2ff4bd6a 100644
--- a/src/cloud/components/organisms/settings/PreferencesTab.tsx
+++ b/src/cloud/components/organisms/settings/PreferencesTab.tsx
@@ -1,22 +1,16 @@
import React from 'react'
-import { TabHeader, Column, Container, Scrollable } from './styled'
import { useTranslation } from 'react-i18next'
import UserPreferencesForm from './UserPreferencesForm'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const PreferencesTab = () => {
const { t } = useTranslation()
return (
-
-
-
-
- {t('settings.preferences')}
-
-
-
-
-
+ }
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/SubscriptionTab.tsx b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
index 3922491182..4332b20e06 100644
--- a/src/cloud/components/organisms/settings/SubscriptionTab.tsx
+++ b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
@@ -1,13 +1,6 @@
import React, { useCallback, useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
-import {
- Column,
- Container,
- Scrollable,
- Section,
- TabHeader,
- StyledSmallFont,
-} from './styled'
+import { StyledSmallFont } from './styled'
import { usePage } from '../../../lib/stores/pageStore'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import { Elements } from '@stripe/react-stripe-js'
@@ -21,6 +14,7 @@ import styled from '../../../lib/styled'
import { stripePublishableKey } from '../../../lib/consts'
import SubscriptionManagement from '../Subscription/SubscriptionManagement'
import UpdateBillingPromoForm from '../../molecules/SubscriptionForm/UpdateBillingPromo'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const stripePromise = loadStripe(stripePublishableKey)
@@ -57,81 +51,75 @@ const SubscriptionTab = () => {
if (currentUserPermissions.role !== 'admin') {
return (
-
-
-
-
-
- Only admins can access this content.
-
-
-
-
-
+
+
+ Only admins can access this content.
+
+
+ }
+ >
)
}
if (subscription != null && subscription.status === 'trialing') {
return (
-
-
-
-
-
- No active subscription. Your trial is underway
-
-
-
-
-
+
+
+ No active subscription. Your trial is underway
+
+
+ }
+ >
)
}
return (
-
-
-
-
-
- {t('settings.teamSubscription')}
- {formtab == null ? (
- setFormTab('email')}
- onMethodClick={() => setFormTab('method')}
- onPromoClick={() => setFormTab('promo')}
- />
- ) : (
-
- {formtab === 'email' ? (
-
+
+ {formtab == null ? (
+ setFormTab('email')}
+ onMethodClick={() => setFormTab('method')}
+ onPromoClick={() => setFormTab('promo')}
+ />
+ ) : (
+
+ {formtab === 'email' ? (
+ setFormTab(undefined)}
+ />
+ ) : formtab === 'method' ? (
+
+ setFormTab(undefined)}
/>
- ) : formtab === 'method' ? (
-
- setFormTab(undefined)}
- />
-
- ) : formtab === 'promo' ? (
- setFormTab(undefined)}
- onCancel={() => setFormTab(undefined)}
- />
- ) : null}
-
- )}
-
-
-
-
-
+
+ ) : formtab === 'promo' ? (
+ setFormTab(undefined)}
+ onCancel={() => setFormTab(undefined)}
+ />
+ ) : null}
+
+ )}
+
+
+ }
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/TeamInfoTab.tsx b/src/cloud/components/organisms/settings/TeamInfoTab.tsx
index 25895c702e..2fa73d2f61 100644
--- a/src/cloud/components/organisms/settings/TeamInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/TeamInfoTab.tsx
@@ -1,19 +1,12 @@
import React, { useMemo } from 'react'
-import {
- Column,
- Scrollable,
- Container,
- Section,
- TabHeader,
- SectionDescription,
- SectionSeparator,
-} from './styled'
+import { SectionDescription, SectionSeparator } from './styled'
import { usePage } from '../../../lib/stores/pageStore'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import { useTranslation } from 'react-i18next'
import { useSettings } from '../../../lib/stores/settings'
import TeamLink from '../../atoms/Link/TeamLink'
import SettingsTeamForm from '../../molecules/SettingsTeamForm'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const TeamInfoTab = () => {
const { team, currentUserPermissions } = usePage()
@@ -33,7 +26,7 @@ const TeamInfoTab = () => {
return (
<>
-
+
Space Deletion
@@ -47,7 +40,7 @@ const TeamInfoTab = () => {
{t('general.delete')}
-
+
>
)
}, [team, , currentUserPermissions, t, closeSettingsTab])
@@ -57,21 +50,15 @@ const TeamInfoTab = () => {
}
return (
-
-
-
- {t('settings.teamInfo')}
-
-
-
-
+
+
+ {adminContent}
+
+ }
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/UpgradeTab.tsx b/src/cloud/components/organisms/settings/UpgradeTab.tsx
index 3a72c192f7..962f0bf3b3 100644
--- a/src/cloud/components/organisms/settings/UpgradeTab.tsx
+++ b/src/cloud/components/organisms/settings/UpgradeTab.tsx
@@ -1,14 +1,6 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
-import {
- Column,
- Scrollable,
- Container,
- Section,
- SectionRow,
- TabHeader,
- StyledSmallFont,
-} from './styled'
+import { SectionRow, StyledSmallFont } from './styled'
import { usePage } from '../../../lib/stores/pageStore'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import { Elements } from '@stripe/react-stripe-js'
@@ -23,6 +15,7 @@ import CustomLink from '../../atoms/Link/CustomLink'
import PlanTables from '../Subscription/PlanTables'
import { UpgradePlans } from '../../../lib/stripe'
import styled from '../../../lib/styled'
+import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
const stripePromise = loadStripe(stripePublishableKey)
@@ -82,15 +75,18 @@ const UpgradeTab = () => {
if (tabState === 'plans') {
return (
-
- {showTrialPopup && (
- setShowTrialPopup(false)} />
- )}
-
-
-
+
+ {showTrialPopup && (
+ setShowTrialPopup(false)}
+ />
+ )}
+
- {t('settings.teamUpgrade')}
{
.
-
-
-
-
+
+ >
+ }
+ >
)
}
return (
-
-
-
-
-
- {t('settings.teamUpgrade')}
-
- {currentUserPermissions.role !== 'admin' ? (
-
- Only admins can access this content.
-
- ) : (
- !(subscription != null && subscription.status === 'active') && (
-
-
-
-
-
- )
- )}
-
-
-
-
-
+
+
+ {currentUserPermissions.role !== 'admin' ? (
+
+ Only admins can access this content.
+
+ ) : (
+ !(subscription != null && subscription.status === 'active') && (
+
+
+
+
+
+ )
+ )}
+
+
+ }
+ >
)
}
From 645cdab34de99c9cdd9f7fdd222e5fcd041b0e57 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 8 May 2021 22:23:45 +0900
Subject: [PATCH 24/91] SettingContent -> SettingMain
---
src/cloud/components/organisms/settings/SettingsComponent.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index 6a1e32a645..54ef420f28 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -27,7 +27,7 @@ import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import Settings from '../../../../shared/components/organisms/Settings'
import SettingSidenavHeader from '../../../../shared/components/organisms/Settings/atoms/SettingSidenavHeader'
import SettingSidenav from '../../../../shared/components/organisms/Settings/atoms/SettingSidenav'
-import SettingContent from '../../../../shared/components/organisms/Settings/atoms/SettingContent'
+import SettingMain from '../../../../shared/components/organisms/Settings/atoms/SettingMain'
import SettingTabButton from '../../../../shared/components/organisms/Settings/atoms/SettingTabButton'
const SettingsComponent = () => {
@@ -196,7 +196,7 @@ const SettingsComponent = () => {
)}
}
- content={{content} }
+ content={{content} }
>
)
}
From b4aeeaf8799cf108e42e4f833a3dc276c5f33701 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 8 May 2021 22:24:10 +0900
Subject: [PATCH 25/91] Removed Unused Components
---
.../settings/UserPreferencesForm.tsx | 6 +-
.../components/organisms/settings/styled.ts | 132 ------------------
2 files changed, 3 insertions(+), 135 deletions(-)
diff --git a/src/cloud/components/organisms/settings/UserPreferencesForm.tsx b/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
index ba59c6d10f..5ad08d424e 100644
--- a/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
+++ b/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
@@ -1,5 +1,5 @@
import React, { useCallback } from 'react'
-import { Section, SectionSelect, SectionHeader3 } from './styled'
+import { SectionSelect, SectionHeader3 } from './styled'
import {
useSettings,
GeneralThemeOptions,
@@ -88,7 +88,7 @@ const UserPreferencesForm = () => {
)
return (
-
+
{t('settings.applicationTheme')}
{t('settings.light')}
@@ -145,7 +145,7 @@ const UserPreferencesForm = () => {
4
2
-
+
)
}
diff --git a/src/cloud/components/organisms/settings/styled.ts b/src/cloud/components/organisms/settings/styled.ts
index cb5d0166d8..5e1d521fe8 100644
--- a/src/cloud/components/organisms/settings/styled.ts
+++ b/src/cloud/components/organisms/settings/styled.ts
@@ -3,58 +3,15 @@ import {
selectStyle,
primaryButtonStyle,
secondaryButtonStyle,
- dangerButtonStyle,
inputStyle,
- tableStyle,
baseIconStyle,
baseButtonStyle,
- paddingLeftMedium,
} from '../../../lib/styled/styleFunctions'
-export const Column = styled.div`
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100%;
-`
-
-export const Container = styled.div`
- max-width: 700px;
- margin: 0 auto;
-`
-
-export const Scrollable = styled.div`
- flex: 1 1 auto;
- width: 100%;
- padding: ${({ theme }) => theme.space.large}px
- ${({ theme }) => theme.space.default}px;
- overflow: hidden auto;
-`
-
export const Section = styled.section`
padding: ${({ theme }) => theme.space.xsmall}px 0;
`
-export const AlignedRightContent = styled.div`
- text-align: right;
-`
-
-export const TabHeader = styled.h2`
- margin-top: 0;
- margin-bottom: ${({ theme }) => theme.space.xsmall}px;
- font-size: ${({ theme }) => theme.fontSizes.medium}px;
- font-weight: 500;
-
- &.marginTop {
- margin-top: ${({ theme }) => theme.space.xsmall}px;
- }
-`
-
-export const SectionHeader1 = styled.h1`
- font-size: ${({ theme }) => theme.fontSizes.xxxsmall * 4}px;
- font-weight: 500;
-`
-
export const SectionHeader2 = styled.h2`
margin: ${({ theme }) => theme.space.medium}px 0
${({ theme }) => theme.space.default}px;
@@ -70,16 +27,6 @@ export const SectionHeader3 = styled.h3`
font-weight: 500;
`
-export const SectionSpan = styled.span`
- display: inline-block;
- width: 60%;
- font-size: ${({ theme }) => theme.fontSizes.xsmall}px;
-`
-
-export const SectionHighlight = styled.span`
- color: ${({ theme }) => theme.primaryBackgroundColor};
-`
-
export const SectionLabel = styled.label`
display: inline-block;
width: 40%;
@@ -106,23 +53,6 @@ export const PrimaryAnchor = styled.a`
}
`
-export const SectionMargin = styled.section`
- margin: ${({ theme }) => theme.space.xlarge * 2}px;
-`
-
-export const SectionControl = styled.div`
- display: flex;
- align-items: center;
- margin-top: ${({ theme }) => theme.space.small}px;
- text-align: right;
- button {
- margin-left: ${({ theme }) => theme.space.xxsmall}px;
- &:first-child {
- margin-left: 0;
- }
- }
-`
-
export const SectionSelect = styled.select`
${selectStyle}
min-width: 200px;
@@ -157,12 +87,6 @@ export const SectionSecondaryButton = styled.button`
align-items: center;
`
-export const SectionDangerButton = styled.button`
- ${baseButtonStyle}
- ${dangerButtonStyle}
- align-items: center;
-`
-
export const SectionList = styled.ul`
margin: 0;
width: 100%;
@@ -205,28 +129,6 @@ export const SectionInLineIcon = styled.span`
${baseIconStyle}
`
-export const SectionIcon = styled.div`
- position: relative;
- width: 50px;
- height: 40px;
- margin-left: 16px;
- border-top-right-radius: 5px;
- border-bottom-right-radius: 5px;
- cursor: pointer;
- text-align: center;
- ${baseIconStyle}
-
- .icon {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- margin: auto;
- width: 1.6em !important;
- }
-`
-
export const SectionInput = styled.input`
${inputStyle}
flex-grow: 1;
@@ -265,31 +167,6 @@ export const SectionFooter = styled.div`
text-align: center;
`
-export const SectionTable = styled.table`
- ${tableStyle}
- margin-top: ${({ theme }) => theme.space.default}px;
- margin-bottom: ${({ theme }) => theme.space.default}px;
-`
-
-export const RightMargin = styled.span`
- margin-right: ${({ theme }) => theme.space.default}px;
-`
-
-export const TopMargin = styled.div`
- margin-top: ${({ theme }) => theme.space.large}px;
-`
-
-export const DeleteStorageButton = styled.button`
- ${baseButtonStyle}
- ${secondaryButtonStyle}
- padding: 0 ${({ theme }) => theme.space.small}px;
- height: 40px;
- border-radius: 2px;
- cursor: pointer;
- vertical-align: middle;
- align-items: center;
-`
-
export const SectionIntroduction = styled.div`
.setHeight {
display: block;
@@ -386,11 +263,6 @@ export const SectionSeparator = styled.div`
height: 1px;
`
-export const StyledWrap = styled.div`
- display: flex;
- justify-content: space-between;
-`
-
export const StyledMembername = styled.div`
display: flex;
align-items: center;
@@ -409,7 +281,3 @@ export const StyledMembername = styled.div`
padding: 2px 5px;
}
`
-
-export const StyledButtonWrap = styled.div`
- ${paddingLeftMedium}
-`
From 490c3ec0256e3db172378a14ace0ba00317e4ef1 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 12:46:24 +0900
Subject: [PATCH 26/91] header -> title
---
.../components/organisms/settings/ApiTab.tsx | 2 +-
.../organisms/settings/AppFeedbackTab.tsx | 2 +-
.../components/organisms/settings/InfoTab.tsx | 2 +-
.../organisms/settings/IntegrationsTab.tsx | 2 +-
.../organisms/settings/MembersTab.tsx | 2 +-
.../organisms/settings/PreferencesTab.tsx | 2 +-
.../organisms/settings/SubscriptionTab.tsx | 2 +-
.../organisms/settings/TeamInfoTab.tsx | 2 +-
.../organisms/settings/UpgradeTab.tsx | 4 +--
.../Settings/atoms/SettingTabContent.tsx | 31 ++++++++++++++++---
10 files changed, 36 insertions(+), 15 deletions(-)
diff --git a/src/cloud/components/organisms/settings/ApiTab.tsx b/src/cloud/components/organisms/settings/ApiTab.tsx
index 1222678e48..b679a686f0 100644
--- a/src/cloud/components/organisms/settings/ApiTab.tsx
+++ b/src/cloud/components/organisms/settings/ApiTab.tsx
@@ -35,7 +35,7 @@ const ApiTab = () => {
return (
diff --git a/src/cloud/components/organisms/settings/AppFeedbackTab.tsx b/src/cloud/components/organisms/settings/AppFeedbackTab.tsx
index 2b40c42d1c..c72ba5cb87 100644
--- a/src/cloud/components/organisms/settings/AppFeedbackTab.tsx
+++ b/src/cloud/components/organisms/settings/AppFeedbackTab.tsx
@@ -8,7 +8,7 @@ const AppFeedbackTab = () => {
return (
diff --git a/src/cloud/components/organisms/settings/InfoTab.tsx b/src/cloud/components/organisms/settings/InfoTab.tsx
index d501425ba3..c08c956d96 100644
--- a/src/cloud/components/organisms/settings/InfoTab.tsx
+++ b/src/cloud/components/organisms/settings/InfoTab.tsx
@@ -84,7 +84,7 @@ const InfoTab = () => {
return (
diff --git a/src/cloud/components/organisms/settings/IntegrationsTab.tsx b/src/cloud/components/organisms/settings/IntegrationsTab.tsx
index cb0df7b9b2..4fed1d3842 100644
--- a/src/cloud/components/organisms/settings/IntegrationsTab.tsx
+++ b/src/cloud/components/organisms/settings/IntegrationsTab.tsx
@@ -42,7 +42,7 @@ const IntegrationsTab = () => {
return (
diff --git a/src/cloud/components/organisms/settings/MembersTab.tsx b/src/cloud/components/organisms/settings/MembersTab.tsx
index b2229b2264..2c45836450 100644
--- a/src/cloud/components/organisms/settings/MembersTab.tsx
+++ b/src/cloud/components/organisms/settings/MembersTab.tsx
@@ -399,7 +399,7 @@ const MembersTab = () => {
if (currentUserPermissions == null || team == null) {
return (
You don't own any permissions.
diff --git a/src/cloud/components/organisms/settings/PreferencesTab.tsx b/src/cloud/components/organisms/settings/PreferencesTab.tsx
index 5d2ff4bd6a..6214e43e7f 100644
--- a/src/cloud/components/organisms/settings/PreferencesTab.tsx
+++ b/src/cloud/components/organisms/settings/PreferencesTab.tsx
@@ -8,7 +8,7 @@ const PreferencesTab = () => {
return (
}
>
)
diff --git a/src/cloud/components/organisms/settings/SubscriptionTab.tsx b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
index 4332b20e06..21b5335666 100644
--- a/src/cloud/components/organisms/settings/SubscriptionTab.tsx
+++ b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
@@ -79,7 +79,7 @@ const SubscriptionTab = () => {
return (
diff --git a/src/cloud/components/organisms/settings/TeamInfoTab.tsx b/src/cloud/components/organisms/settings/TeamInfoTab.tsx
index 2fa73d2f61..bf85753816 100644
--- a/src/cloud/components/organisms/settings/TeamInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/TeamInfoTab.tsx
@@ -51,7 +51,7 @@ const TeamInfoTab = () => {
return (
diff --git a/src/cloud/components/organisms/settings/UpgradeTab.tsx b/src/cloud/components/organisms/settings/UpgradeTab.tsx
index 962f0bf3b3..d72cbfdc7c 100644
--- a/src/cloud/components/organisms/settings/UpgradeTab.tsx
+++ b/src/cloud/components/organisms/settings/UpgradeTab.tsx
@@ -76,7 +76,7 @@ const UpgradeTab = () => {
if (tabState === 'plans') {
return (
{showTrialPopup && (
@@ -118,7 +118,7 @@ const UpgradeTab = () => {
return (
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
index 14d0954018..75cbed5e3e 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
@@ -2,15 +2,23 @@ import React from 'react'
import styled from '../../../../lib/styled'
interface SettingTabContentProps {
- header?: React.ReactNode
+ title?: React.ReactNode
+ description?: React.ReactNode
body: React.ReactNode
}
-const SettingTabContent = ({ header, body }: SettingTabContentProps) => (
+const SettingTabContent = ({
+ title,
+ description,
+ body,
+}: SettingTabContentProps) => (
-
{header}
+
+
{title}
+
{description}
+
{body}
@@ -22,6 +30,7 @@ const Container = styled.div`
flex-direction: column;
width: 100%;
height: 100%;
+ padding-top: ${({ theme }) => theme.sizes.spaces.xl}px;
.tab-content__scrollable {
flex: 1 1 auto;
@@ -37,10 +46,22 @@ const Container = styled.div`
}
.tab-content__header {
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.md}px;
+ padding-bottom: ${({ theme }) => theme.sizes.spaces.md}px;
+ border-bottom: 1px solid ${({ theme }) => theme.colors.border.main};
+ }
+
+ .tab-content__header__title {
margin-top: 0;
margin-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px;
- font-size: ${({ theme }) => theme.sizes.fonts.xl}px;
- font-weight: 500;
+ font-size: ${({ theme }) => theme.sizes.fonts.l}px;
+ font-weight: normal;
+ }
+
+ .tab-content__header__description {
+ margin-bottom: 0;
+ color: ${({ theme }) => theme.colors.text.subtle};
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
}
.tab-content__body {
From f50c551f586f08b96be5da98245acc2cefbc5c44 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 14:37:16 +0900
Subject: [PATCH 27/91] Added SettingInput
---
.../organisms/Settings/atoms/SettingInput.tsx | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingInput.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingInput.tsx b/src/shared/components/organisms/Settings/atoms/SettingInput.tsx
new file mode 100644
index 0000000000..3ebb720239
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingInput.tsx
@@ -0,0 +1,47 @@
+import React from 'react'
+import styled from '../../../../lib/styled'
+
+interface SettingInputProps {
+ label?: string
+ value?: string
+ onChange?: React.ChangeEventHandler
+}
+
+const SettingInput = ({ label, value, onChange }: SettingInputProps) => (
+
+ {label}
+
+
+)
+
+const Container = styled.div`
+ label {
+ display: block;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
+ color: ${({ theme }) => theme.colors.text.secondary};
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+ }
+
+ input {
+ flex-grow: 1;
+ flex-shrink: 1;
+ width: 100%;
+ height: 40px;
+ max-width: 400px;
+ padding: ${({ theme }) => theme.sizes.spaces.xsm}px
+ ${({ theme }) => theme.sizes.spaces.sm}px;
+ background-color: ${({ theme }) => theme.colors.background.primary};
+ border: 1px solid ${({ theme }) => theme.colors.border.main};
+ border-radius: 4px;
+ color: ${({ theme }) => theme.colors.text.primary};
+
+ &:focus {
+ border-color: ${({ theme }) => theme.colors.variants.primary.base};
+ }
+ &::placeholder {
+ color: ${({ theme }) => theme.colors.text.subtle};
+ }
+ }
+`
+
+export default SettingInput
From 9c2f2c4f1a936ee84e982883ef795329cfcfcb85 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 14:37:29 +0900
Subject: [PATCH 28/91] Added SettingSelect
---
.../Settings/atoms/SettingSelect.tsx | 55 +++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx b/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
new file mode 100644
index 0000000000..408d7c87b7
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
@@ -0,0 +1,55 @@
+import React from 'react'
+import styled from '../../../../lib/styled'
+
+interface SettingSelectProps {
+ label?: string
+ value?: string
+ disabled?: boolean
+ onChange?: (val: any) => void
+ options: React.ReactNode
+}
+
+const SettingSelect = ({
+ label,
+ value,
+ disabled,
+ onChange,
+ options,
+}: SettingSelectProps) => (
+
+ {label}
+
+ {options}
+
+
+)
+
+const Container = styled.div`
+ label {
+ display: block;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
+ color: ${({ theme }) => theme.colors.text.secondary};
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+ }
+
+ select {
+ width: 100%;
+ height: 40px;
+ max-width: 400px;
+ padding: 0 ${({ theme }) => theme.sizes.spaces.sm}px;
+ border-radius: 4px;
+ background-color: ${({ theme }) => theme.colors.background.primary};
+ border: 1px solid ${({ theme }) => theme.colors.border.main};
+ color: ${({ theme }) => theme.colors.text.primary};
+
+ &:focus {
+ border-color: ${({ theme }) => theme.colors.variants.primary.base};
+ }
+
+ option {
+ color: initial;
+ }
+ }
+`
+
+export default SettingSelect
From 77bfc7091ea960761fca1d941fe5450ee3972062 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 14:37:47 +0900
Subject: [PATCH 29/91] Added tab-content__footer
---
.../Settings/atoms/SettingTabContent.tsx | 20 ++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
index 75cbed5e3e..41477a6f3f 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
@@ -5,12 +5,14 @@ interface SettingTabContentProps {
title?: React.ReactNode
description?: React.ReactNode
body: React.ReactNode
+ footer?: React.ReactNode
}
const SettingTabContent = ({
title,
description,
body,
+ footer,
}: SettingTabContentProps) => (
@@ -20,6 +22,7 @@ const SettingTabContent = ({
{description}
{body}
+ {footer}
@@ -66,7 +69,22 @@ const Container = styled.div`
.tab-content__body {
section {
- padding: ${({ theme }) => theme.sizes.spaces.xsm}px 0;
+ margin: ${({ theme }) => theme.sizes.spaces.md}px 0;
+ }
+ }
+
+ .tab-content__footer {
+ margin-top: ${({ theme }) => theme.sizes.spaces.md}px;
+ padding-top: ${({ theme }) => theme.sizes.spaces.md}px;
+ border-top: 1px solid ${({ theme }) => theme.colors.border.main};
+
+ h2 {
+ font-size: ${({ theme }) => theme.sizes.fonts.md}px;
+ font-weight: normal;
+ }
+
+ p {
+ color: ${({ theme }) => theme.colors.text.subtle};
}
}
`
From 045bd4918282c20bb4937e9d9fef629a9e26f746 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 14:37:59 +0900
Subject: [PATCH 30/91] Added More Padding to Buttons
---
src/shared/components/atoms/Button.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/components/atoms/Button.tsx b/src/shared/components/atoms/Button.tsx
index d3dddefbd5..d912e43fca 100644
--- a/src/shared/components/atoms/Button.tsx
+++ b/src/shared/components/atoms/Button.tsx
@@ -143,7 +143,7 @@ export const LoadingButton = ({
export default Button
const StyledButton = styled.button`
- padding: 0 10px;
+ padding: 0 ${({ theme }) => theme.sizes.spaces.md}px;
border-radius: 2px;
font-size: ${({ theme }) => theme.sizes.fonts.df}px;
height: 32px;
From 262caf6d7aa9944c3000ded3e6cfcb51ebd9668d Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 14:38:12 +0900
Subject: [PATCH 31/91] Updated PersonalInfoTab
---
.../organisms/settings/PersonalInfoTab.tsx | 133 ++++++++----------
src/cloud/lib/i18n/enUS.ts | 2 +-
2 files changed, 61 insertions(+), 74 deletions(-)
diff --git a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
index 24384208d2..bdf2fb4c42 100644
--- a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
@@ -1,21 +1,9 @@
import React, { useCallback, useState, useMemo } from 'react'
-import {
- SectionLabel,
- SectionInput,
- SectionProfilePic,
- SectionFlexLeft,
- SectionSeparator,
- SectionDescription,
- SectionSelect,
- SectionHeader3,
- SectionHeader2,
-} from './styled'
import { useTranslation } from 'react-i18next'
import { useGlobalData } from '../../../lib/stores/globalData'
import { saveUserInfo, updateUserIcon } from '../../../api/users'
import { buildIconUrl } from '../../../api/files'
import IconInput from '../../molecules/IconInput'
-import CustomButton from '../../atoms/buttons/CustomButton'
import { Spinner } from '../../atoms/Spinner'
import { useSettings } from '../../../lib/stores/settings'
import AccountLink from '../../atoms/Link/AccountLink'
@@ -24,6 +12,9 @@ import { UserEmailNotificationType } from '../../../interfaces/db/userSettings'
import { saveUserSettings } from '../../../api/users/settings'
import { useToast } from '../../../../shared/lib/stores/toast'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
+import SettingInput from '../../../../shared/components/organisms/Settings/atoms/SettingInput'
+import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
+import Button from '../../../../shared/components/atoms/Button'
const PersonalInfoTab = () => {
const {
@@ -119,37 +110,38 @@ const PersonalInfoTab = () => {
return (
-
- {currentUser != null && (
- <>
- Display Name
-
-
- Icon
-
-
- >
- )}
+ {currentUser != null && (
+ <>
+
+
+ >
+ )}
- {currentUser != null && (
- <>
- {t('settings.notifications')}
-
-
- {t('settings.notificationsFrequency')}
-
-
+ {currentUser != null && (
+
-
- >
- )}
+ >
+ }
+ >
+
+ )}
-
-
- {updating ? (
-
- ) : (
- t('general.update')
- )}
-
-
- {t('general.cancel')}
-
-
-
-
-
- {t('settings.account.delete')}
-
-
- You may delete your account at any time, note that this is
- unrecoverable.{' '}
-
- {t('general.delete')}
-
-
+
+ {updating ? (
+
+ ) : (
+ t('general.update')
+ )}
+
>
}
+ footer={
+ <>
+ {t('settings.account.delete')}
+
+ You may delete your account at any time, note that this is
+ unrecoverable.{' '}
+
+ {t('general.delete')}
+
+
+ >
+ }
>
)
}
diff --git a/src/cloud/lib/i18n/enUS.ts b/src/cloud/lib/i18n/enUS.ts
index 0de2144b6f..99fd43894a 100644
--- a/src/cloud/lib/i18n/enUS.ts
+++ b/src/cloud/lib/i18n/enUS.ts
@@ -40,7 +40,7 @@ const enTranslation: TranslationSource = {
'settings.editorKeyMap': 'Editor Keymap',
'settings.light': 'Light',
'settings.dark': 'Dark',
- 'settings.notificationsFrequency': 'Notification frequency',
+ 'settings.notificationsFrequency': 'Email updates',
// Settings Community
'community.feature.requests': 'Feature Requests',
From b91a2d88bf5fc3dcc755e59b9fa5c6213ba4ded7 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 18:44:59 +0900
Subject: [PATCH 32/91] Removed Unused Files
---
.../organisms/settings/AppFeedbackTab.tsx | 21 ---
.../components/organisms/settings/InfoTab.tsx | 157 ------------------
.../organisms/settings/SettingsFooter.tsx | 44 -----
.../components/organisms/settings/TabLink.tsx | 67 --------
4 files changed, 289 deletions(-)
delete mode 100644 src/cloud/components/organisms/settings/AppFeedbackTab.tsx
delete mode 100644 src/cloud/components/organisms/settings/InfoTab.tsx
delete mode 100644 src/cloud/components/organisms/settings/SettingsFooter.tsx
delete mode 100644 src/cloud/components/organisms/settings/TabLink.tsx
diff --git a/src/cloud/components/organisms/settings/AppFeedbackTab.tsx b/src/cloud/components/organisms/settings/AppFeedbackTab.tsx
deleted file mode 100644
index c72ba5cb87..0000000000
--- a/src/cloud/components/organisms/settings/AppFeedbackTab.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react'
-import { useTranslation } from 'react-i18next'
-import AppFeedbackForm from '../../molecules/AppFeedbackForm'
-import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
-
-const AppFeedbackTab = () => {
- const { t } = useTranslation()
-
- return (
-
-
-
- }
- >
- )
-}
-
-export default AppFeedbackTab
diff --git a/src/cloud/components/organisms/settings/InfoTab.tsx b/src/cloud/components/organisms/settings/InfoTab.tsx
deleted file mode 100644
index c08c956d96..0000000000
--- a/src/cloud/components/organisms/settings/InfoTab.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-import React, { useCallback, useState, useMemo } from 'react'
-import {
- SectionLabel,
- SectionInput,
- SectionProfilePic,
- SectionFlexLeft,
- SectionSeparator,
- SectionDescription,
-} from './styled'
-import { useTranslation } from 'react-i18next'
-import { useGlobalData } from '../../../lib/stores/globalData'
-import { saveUserInfo, updateUserIcon } from '../../../api/users'
-import { buildIconUrl } from '../../../api/files'
-import IconInput from '../../molecules/IconInput'
-import CustomButton from '../../atoms/buttons/CustomButton'
-import { Spinner } from '../../atoms/Spinner'
-import { useSettings } from '../../../lib/stores/settings'
-import AccountLink from '../../atoms/Link/AccountLink'
-import styled from '../../../lib/styled'
-import {
- baseButtonStyle,
- dangerButtonStyle,
-} from '../../../lib/styled/styleFunctions'
-import { useToast } from '../../../../shared/lib/stores/toast'
-import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
-
-const InfoTab = () => {
- const {
- globalData: { currentUser },
- setPartialGlobalData,
- } = useGlobalData()
-
- const { pushMessage } = useToast()
- const [updating, setUpdating] = useState(false)
- const [displayName, setDisplayName] = useState(
- currentUser != null ? currentUser.displayName : ''
- )
- const [iconFile, setIconFile] = useState(null)
- const { t } = useTranslation()
- const { closeSettingsTab } = useSettings()
-
- const onChangeHandler = useCallback(
- (event: React.ChangeEvent) => {
- setDisplayName(event.target.value)
- },
- [setDisplayName]
- )
-
- const updateHandler = useCallback(async () => {
- if (updating) {
- return
- }
- setUpdating(true)
- try {
- await saveUserInfo({ displayName })
- const user = { ...currentUser!, displayName }
- if (iconFile != null) {
- const { icon } = await updateUserIcon(iconFile)
- user.icon = icon
- }
- setPartialGlobalData({ currentUser: user })
- } catch (error) {
- pushMessage({
- title: 'Error',
- description: `Could not update your user information`,
- })
- }
- setUpdating(false)
- }, [
- updating,
- displayName,
- currentUser,
- iconFile,
- setPartialGlobalData,
- pushMessage,
- ])
-
- const iconUrl = useMemo(() => {
- if (currentUser == null || currentUser.icon == null) {
- return undefined
- }
- return buildIconUrl(currentUser.icon.location)
- }, [currentUser])
-
- return (
-
-
- {currentUser != null && (
- <>
- Display Name
-
-
- Icon
-
-
- >
- )}
-
-
- {updating ? (
-
- ) : (
- t('general.update')
- )}
-
-
- {t('general.cancel')}
-
-
-
-
-
-
-
- {t('settings.account.delete')}
-
-
- You may delete your account at any time, note that this is
- unrecoverable.{' '}
-
-
- {t('general.delete')}
-
-
-
- >
- }
- >
- )
-}
-
-const StyledInfoTabDelete = styled.div`
- .delete-link {
- ${baseButtonStyle}
- ${dangerButtonStyle}
- display: inline-block;
- text-decoration: none;
- }
-`
-
-export default InfoTab
diff --git a/src/cloud/components/organisms/settings/SettingsFooter.tsx b/src/cloud/components/organisms/settings/SettingsFooter.tsx
deleted file mode 100644
index 04bea9c2f0..0000000000
--- a/src/cloud/components/organisms/settings/SettingsFooter.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import React, { useCallback } from 'react'
-import { SectionFooter } from './styled'
-import { useSettings } from '../../../lib/stores/settings'
-import { useTranslation } from 'react-i18next'
-import CustomButton from '../../atoms/buttons/CustomButton'
-import { Spinner } from '../../atoms/Spinner'
-
-interface SettingsFooterProps {
- onUpdate: () => void
- updating: boolean
- disabled: boolean
-}
-
-const SettingsFooter = ({
- onUpdate,
- updating,
- disabled,
-}: SettingsFooterProps) => {
- const { setClosed } = useSettings()
-
- const onCancelHandler = useCallback(() => {
- setClosed(true)
- }, [setClosed])
-
- const { t } = useTranslation()
-
- return (
-
-
- {updating ? : t('general.update')}
-
-
- {t('general.cancel')}
-
-
- )
-}
-
-export default SettingsFooter
diff --git a/src/cloud/components/organisms/settings/TabLink.tsx b/src/cloud/components/organisms/settings/TabLink.tsx
deleted file mode 100644
index 8c9e515d13..0000000000
--- a/src/cloud/components/organisms/settings/TabLink.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from 'react'
-import styled from '../../../lib/styled'
-import Icon from '../../atoms/IconMdi'
-import { mdiOpenInNew } from '@mdi/js'
-
-interface TabLinkProps {
- label: string
- href: string
- id?: string
- prependIcon: string
-}
-
-const TabLink = ({ id, label, href, prependIcon }: TabLinkProps) => {
- return (
-
-
-
-
- {label}
-
-
- )
-}
-
-export default TabLink
-
-const StyledLink = styled.a`
- display: flex;
- align-items: center;
- width: 100%;
- padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.small}px;
- background-color: transparent;
- border: none;
- color: ${({ theme }) => theme.subtleTextColor};
- cursor: pointer;
- text-decoration: none !important;
-
- .icon {
- margin-left: ${({ theme }) => theme.space.small}px;
- margin-right: ${({ theme }) => theme.space.xsmall}px;
-
- svg {
- vertical-align: sub;
- }
- }
-
- .label {
- flex: 1;
- font-size: ${({ theme }) => theme.fontSizes.small}px;
- text-align: left;
- }
-
- &.active,
- &:hover,
- &:focus {
- color: ${({ theme }) => theme.emphasizedTextColor};
- }
-
- &.active {
- background-color: ${({ theme }) => theme.emphasizedBackgroundColor};
- }
-
- &:focus {
- outline: none;
- }
-`
From 205e7b1d571e2f38bcbe316044fce14f723aa62c Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 18:45:35 +0900
Subject: [PATCH 33/91] Updated Title
---
src/cloud/lib/i18n/enUS.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cloud/lib/i18n/enUS.ts b/src/cloud/lib/i18n/enUS.ts
index 99fd43894a..42b9b33c41 100644
--- a/src/cloud/lib/i18n/enUS.ts
+++ b/src/cloud/lib/i18n/enUS.ts
@@ -23,7 +23,7 @@ const enTranslation: TranslationSource = {
'settings.teamInfo': 'Settings',
'settings.title': 'Settings',
'settings.personalInfo': 'Settings',
- 'settings.preferences': 'Theme and Preferences',
+ 'settings.preferences': 'Preferences',
'settings.teamMembers': 'Members',
'settings.teamUpgrade': 'Upgrade',
'settings.teamSubscription': 'Billing',
From 9ff291c7b1fe752146e45533c6f1feb3f639a033 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 18:46:01 +0900
Subject: [PATCH 34/91] Added Setting Divider
---
.../organisms/Settings/atoms/SettingDivider.tsx | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingDivider.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingDivider.tsx b/src/shared/components/organisms/Settings/atoms/SettingDivider.tsx
new file mode 100644
index 0000000000..ddc5acf07a
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingDivider.tsx
@@ -0,0 +1,11 @@
+import styled from '../../../../lib/styled'
+
+const SettingDivider = styled.div`
+ margin-top: ${({ theme }) => theme.sizes.spaces.l}px;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.l}px;
+ width: 100%;
+ height: 1px;
+ background-color: ${({ theme }) => theme.colors.border.main};
+`
+
+export default SettingDivider
From cb8fa37dec47b5925281f9b7ad6eeb85b6f12093 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 18:46:15 +0900
Subject: [PATCH 35/91] Added SettingLink
---
.../organisms/Settings/atoms/SettingLink.tsx | 13 +++++++++++++
1 file changed, 13 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingLink.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingLink.tsx b/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
new file mode 100644
index 0000000000..489a2eae99
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
@@ -0,0 +1,13 @@
+import styled from '../../../../lib/styled'
+
+const SettingLink = styled.a`
+ color: ${({ theme }) => theme.colors.text.link};
+ text-decoration: none;
+
+ &:hover {
+ color: ${({ theme }) => theme.colors.text.link};
+ text-decoration: underline;
+ }
+`
+
+export default SettingLink
From 9d048c9cd21bc168fb22b0f2dfcb1fcd04328979 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 18:46:27 +0900
Subject: [PATCH 36/91] Added SettingTextarea
---
.../Settings/atoms/SettingTextarea.tsx | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingTextarea.tsx
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTextarea.tsx b/src/shared/components/organisms/Settings/atoms/SettingTextarea.tsx
new file mode 100644
index 0000000000..51c5c89f5c
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingTextarea.tsx
@@ -0,0 +1,25 @@
+import styled from '../../../../lib/styled'
+
+const SettingTextarea = styled.textarea`
+ flex-grow: 1;
+ flex-shrink: 1;
+ width: 100%;
+ height: 200px;
+ max-width: 400px;
+ padding: ${({ theme }) => theme.sizes.spaces.xsm}px
+ ${({ theme }) => theme.sizes.spaces.sm}px;
+ background-color: ${({ theme }) => theme.colors.background.primary};
+ border: 1px solid ${({ theme }) => theme.colors.border.main};
+ border-radius: 4px;
+ color: ${({ theme }) => theme.colors.text.primary};
+ resize: none;
+
+ &:focus {
+ border-color: ${({ theme }) => theme.colors.variants.primary.base};
+ }
+ &::placeholder {
+ color: ${({ theme }) => theme.colors.text.subtle};
+ }
+`
+
+export default SettingTextarea
From adc600aab8e8eec49f4bb490c59c8560f8d8f416 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 18:46:50 +0900
Subject: [PATCH 37/91] Updated SettingTabContent
---
.../Settings/atoms/SettingTabContent.tsx | 27 ++++++++++---------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
index 41477a6f3f..097f74ffdf 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
@@ -49,8 +49,8 @@ const Container = styled.div`
}
.tab-content__header {
- margin-bottom: ${({ theme }) => theme.sizes.spaces.md}px;
- padding-bottom: ${({ theme }) => theme.sizes.spaces.md}px;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.l}px;
+ padding-bottom: ${({ theme }) => theme.sizes.spaces.l}px;
border-bottom: 1px solid ${({ theme }) => theme.colors.border.main};
}
@@ -67,25 +67,26 @@ const Container = styled.div`
font-size: ${({ theme }) => theme.sizes.fonts.df}px;
}
- .tab-content__body {
- section {
- margin: ${({ theme }) => theme.sizes.spaces.md}px 0;
- }
- }
-
+ .tab-content__body,
.tab-content__footer {
- margin-top: ${({ theme }) => theme.sizes.spaces.md}px;
- padding-top: ${({ theme }) => theme.sizes.spaces.md}px;
- border-top: 1px solid ${({ theme }) => theme.colors.border.main};
-
h2 {
font-size: ${({ theme }) => theme.sizes.fonts.md}px;
font-weight: normal;
}
- p {
+ .text--subtle {
color: ${({ theme }) => theme.colors.text.subtle};
}
+
+ .text--small {
+ font-size: ${({ theme }) => theme.sizes.fonts.sm}px;
+ }
+ }
+
+ .tab-content__body {
+ section {
+ margin: ${({ theme }) => theme.sizes.spaces.md}px 0;
+ }
}
`
From 635fb6e7efdfe63bb998c713de18dcb5cd17162c Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 18:52:17 +0900
Subject: [PATCH 38/91] Removed Components from styled.ts
---
.../molecules/AppFeedbackForm/index.tsx | 33 ++--
.../molecules/GuestInvitesSection.tsx | 12 +-
.../molecules/OpenInviteSection.tsx | 14 +-
.../components/molecules/SettingsTeamForm.tsx | 4 +-
.../molecules/SubscriptionForm/index.tsx | 29 ++-
.../molecules/TeamInvitesSection.tsx | 29 +--
.../components/molecules/TokenCreate.tsx | 19 +-
.../Modal/contents/Doc/GuestsModal/index.tsx | 6 +-
.../Subscription/SubscriptionManagement.tsx | 18 +-
.../components/organisms/settings/ApiTab.tsx | 21 ++-
.../organisms/settings/IntegrationsTab.tsx | 133 +++++++-------
.../organisms/settings/MembersTab.tsx | 99 +++++-----
.../organisms/settings/PersonalInfoTab.tsx | 4 +-
.../organisms/settings/PreferencesTab.tsx | 1 +
.../organisms/settings/SubscriptionTab.tsx | 5 +-
.../organisms/settings/TeamInfoTab.tsx | 14 +-
.../organisms/settings/UpgradeTab.tsx | 11 +-
.../settings/UserPreferencesForm.tsx | 153 ++++++++++------
.../components/organisms/settings/styled.ts | 169 +-----------------
19 files changed, 321 insertions(+), 453 deletions(-)
diff --git a/src/cloud/components/molecules/AppFeedbackForm/index.tsx b/src/cloud/components/molecules/AppFeedbackForm/index.tsx
index b1f40c3a61..9a8a436871 100644
--- a/src/cloud/components/molecules/AppFeedbackForm/index.tsx
+++ b/src/cloud/components/molecules/AppFeedbackForm/index.tsx
@@ -3,16 +3,13 @@ import CustomButton from '../../atoms/buttons/CustomButton'
import { Spinner } from '../../atoms/Spinner'
import { StyledAppFeedbackForm } from './styled'
import { SelectChangeEventHandler } from '../../../lib/utils/events'
-import {
- SectionSelect,
- SectionHeader2,
- SectionTextarea,
-} from '../../organisms/settings/styled'
import { registerAppFeedback } from '../../../api/users/appfeedback'
import { AppFeedbackTypeOption } from '../../../interfaces/db/userAppFeedback'
import ColoredBlock from '../../atoms/ColoredBlock'
import { useEffectOnce } from 'react-use'
import { useToast } from '../../../../shared/lib/stores/toast'
+import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
+import SettingTextarea from '../../../../shared/components/organisms/Settings/atoms/SettingTextarea'
const typeOptions: AppFeedbackTypeOption[] = ['Feature Request', 'Bug Report']
@@ -98,17 +95,23 @@ const AppFeedbackForm = () => {
return (
- Type of feedback
-
- {typeOptions.map((val) => (
-
- {val}
-
- ))}
-
+ Type of feedback
+
+ {typeOptions.map((val) => (
+
+ {val}
+
+ ))}
+ >
+ }
+ >
- Free form
- Free form
+ {
)
return (
-
+
- Invite with Email
+ Invite with Email
{has('fetch') && }
+
)
}
diff --git a/src/cloud/components/molecules/OpenInviteSection.tsx b/src/cloud/components/molecules/OpenInviteSection.tsx
index 15e00b4b0c..166fe6a70f 100644
--- a/src/cloud/components/molecules/OpenInviteSection.tsx
+++ b/src/cloud/components/molecules/OpenInviteSection.tsx
@@ -1,9 +1,5 @@
import React, { useState, useCallback, useMemo } from 'react'
-import {
- Section,
- SectionHeader2,
- SectionRow,
-} from '../organisms/settings/styled'
+import { SectionRow } from '../organisms/settings/styled'
import { useDialog, DialogIconTypes } from '../../../shared/lib/stores/dialog'
import { usePage } from '../../lib/stores/pageStore'
import { useEffectOnce } from 'react-use'
@@ -172,11 +168,9 @@ const OpenInvitesSection = ({ userPermissions }: OpenInvitesSectionProps) => {
}
return (
-
+
-
- Invite with an open Link
-
+ Invite with an open Link
{
)}
-
+
)
}
diff --git a/src/cloud/components/molecules/SettingsTeamForm.tsx b/src/cloud/components/molecules/SettingsTeamForm.tsx
index 5bc08d138c..2c60b270f5 100644
--- a/src/cloud/components/molecules/SettingsTeamForm.tsx
+++ b/src/cloud/components/molecules/SettingsTeamForm.tsx
@@ -13,13 +13,13 @@ import {
inputStyle,
inverseSecondaryButtonStyle,
} from '../../lib/styled/styleFunctions'
-import Button from '../atoms/Button'
import Flexbox from '../atoms/Flexbox'
import Icon from '../atoms/Icon'
import { Spinner } from '../atoms/Spinner'
import { useRouter } from '../../lib/router'
import { getTeamURL } from '../../lib/utils/patterns'
import { useToast } from '../../../shared/lib/stores/toast'
+import Button from '../../../shared/components/atoms/Button'
interface SettingsTeamFormProps {
team: SerializedTeam
@@ -144,7 +144,7 @@ const SettingsTeamForm = ({
{onCancel != null && (
-
+
@@ -201,7 +196,7 @@ const SubscriptionForm = ({
Total Monthly Price
{totalMonthlyPrice}
-
+
{usingJpyPricing && (
We can only accept JPY(Japanese Yen) when paying by JCB cards.
@@ -221,11 +216,7 @@ const SubscriptionForm = ({
value={email}
onChange={onEmailInputChangeHandler}
/>
- {ongoingTrial != null && (
-
- Your free trial will be stopped.
-
- )}
+ {ongoingTrial != null && Your free trial will be stopped.
}
{onCancel != null && (
-
Cancel
-
+
)}
-
{sending ? : 'Subscribe'}
-
+
)
diff --git a/src/cloud/components/molecules/TeamInvitesSection.tsx b/src/cloud/components/molecules/TeamInvitesSection.tsx
index 377030962b..4fea03f301 100644
--- a/src/cloud/components/molecules/TeamInvitesSection.tsx
+++ b/src/cloud/components/molecules/TeamInvitesSection.tsx
@@ -1,13 +1,9 @@
import React, { useState, useCallback } from 'react'
import {
- Section,
- SectionHeader2,
SectionRow,
- SectionInput,
SectionList,
SectionListItem,
SectionInLineIcon,
- SectionSelect,
} from '../organisms/settings/styled'
import { SerializedTeamInvite } from '../../interfaces/db/teamInvite'
import { useDialog, DialogIconTypes } from '../../../shared/lib/stores/dialog'
@@ -27,6 +23,8 @@ import CustomButton from '../atoms/buttons/CustomButton'
import { SelectChangeEventHandler } from '../../lib/utils/events'
import { SerializedUserTeamPermissions } from '../../interfaces/db/userTeamPermissions'
import Flexbox from '../atoms/Flexbox'
+import SettingSelect from '../../../shared/components/organisms/Settings/atoms/SettingSelect'
+import SettingInput from '../../../shared/components/organisms/Settings/atoms/SettingInput'
interface TeamInvitesSectionProps {
userPermissions: SerializedUserTeamPermissions
@@ -144,27 +142,30 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
)
return (
-
+
- Invite with Email
+ Invite with Email
{sending && }
+
)
}
diff --git a/src/cloud/components/molecules/TokenCreate.tsx b/src/cloud/components/molecules/TokenCreate.tsx
index f27252826d..134b7488cf 100644
--- a/src/cloud/components/molecules/TokenCreate.tsx
+++ b/src/cloud/components/molecules/TokenCreate.tsx
@@ -1,13 +1,8 @@
import React, { useState, useCallback, ChangeEvent } from 'react'
import CustomButton from '../atoms/buttons/CustomButton'
-import {
- Section,
- SectionInput,
- SectionLabel,
-} from '../organisms/settings/styled'
import Flexbox from '../atoms/Flexbox'
import styled from '../../lib/styled'
-import { SectionHeader2 } from '../organisms/Modal/contents/styled'
+import SettingInput from '../../../shared/components/organisms/Settings/atoms/SettingInput'
interface TokenCreateProps {
onCreate: (name: string) => void
@@ -22,16 +17,16 @@ const TokenCreate = ({ onCreate }: TokenCreateProps) => {
return (
- Create a token
-
- Name
- Create a token
+
+ ) =>
setName(e.target.value)
}
- />
-
+ >
+
{name.length === 0 && (
Enter a name
diff --git a/src/cloud/components/organisms/Modal/contents/Doc/GuestsModal/index.tsx b/src/cloud/components/organisms/Modal/contents/Doc/GuestsModal/index.tsx
index fd1316c5a0..6d9c8fb4c8 100644
--- a/src/cloud/components/organisms/Modal/contents/Doc/GuestsModal/index.tsx
+++ b/src/cloud/components/organisms/Modal/contents/Doc/GuestsModal/index.tsx
@@ -9,8 +9,8 @@ import Icon from '../../../../../atoms/Icon'
import { guestsPerMember } from '../../../../../../lib/subscription'
import plur from 'plur'
import GuestInvitesSection from '../../../../../molecules/GuestInvitesSection'
-import { PrimaryAnchor } from '../../../../settings/styled'
import { useModal } from '../../../../../../../shared/lib/stores/modal'
+import SettingLink from '../../../../../../../shared/components/organisms/Settings/atoms/SettingLink'
interface GuestsModalProps {
docId: string
@@ -64,13 +64,13 @@ const GuestsModal = ({ docId, teamId }: GuestsModalProps) => {
permissions.length * guestsPerMember - guestsMap.size
} remaining ${plur('seat', permissions.length)}. `
: 'No Remaining seats. '}
-
See how it works
-
+
diff --git a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx b/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
index eef6520e1c..07eb900767 100644
--- a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
+++ b/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
@@ -26,7 +26,7 @@ import {
StyledTotal,
StyledUpgradePlan,
} from '../../molecules/SubscriptionForm'
-import { SectionIntroduction, SectionParagraph } from '../settings/styled'
+import { SectionIntroduction } from '../settings/styled'
import PlanTables from './PlanTables'
import Alert from '../../../../components/atoms/Alert'
@@ -140,7 +140,7 @@ const SubscriptionManagement = ({
{subscription.plan === 'pro' ? (
-
+
Pro
@@ -165,9 +165,9 @@ const SubscriptionManagement = ({
: `¥${stripeProJpyPlanUnit * subscription.seats}`}
-
+
) : subscription.plan === 'standard' ? (
-
+
Standard
@@ -191,7 +191,7 @@ const SubscriptionManagement = ({
: `¥${stripeStandardJpyPlanUnit * subscription.seats}`}
-
+
) : null}
{usingJpyPricing && (
@@ -337,7 +337,7 @@ const SubscriptionManagement = ({
-
+
${stripeProPlanUnit} × {subscription.seats}{' '}
@@ -348,7 +348,7 @@ const SubscriptionManagement = ({
Total Monthly Price
${subscription.seats * stripeProPlanUnit}
-
+
>
) : (
<>
@@ -368,7 +368,7 @@ const SubscriptionManagement = ({
-
+
${stripeStandardPlanUnit} × {subscription.seats}{' '}
@@ -381,7 +381,7 @@ const SubscriptionManagement = ({
${subscription.seats * stripeStandardPlanUnit}
-
+
>
)}
diff --git a/src/cloud/components/organisms/settings/ApiTab.tsx b/src/cloud/components/organisms/settings/ApiTab.tsx
index b679a686f0..9d5ba08a9a 100644
--- a/src/cloud/components/organisms/settings/ApiTab.tsx
+++ b/src/cloud/components/organisms/settings/ApiTab.tsx
@@ -1,7 +1,5 @@
import React, { useCallback, useMemo, useState } from 'react'
import styled from '../../../lib/styled'
-import { SectionSubtleText, SectionHeader2, PrimaryAnchor } from './styled'
-import CustomButton from '../../atoms/buttons/CustomButton'
import Spinner from '../../atoms/CustomSpinner'
import { useApiTokens, withApiTokens } from '../../../lib/stores/apiTokens'
import TokenControl from '../../molecules/TokenControl'
@@ -11,6 +9,8 @@ import Flexbox from '../../atoms/Flexbox'
import Icon from '../../atoms/IconMdi'
import { mdiOpenInNew } from '@mdi/js'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
+import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
+import Button from '../../../../shared/components/atoms/Button'
const ApiTab = () => {
const { team } = usePage()
@@ -36,37 +36,36 @@ const ApiTab = () => {
return (
-
+
These tokens are available only to{' '}
{team != null ? team.name : 'your team'}.
-
+
-
- Access Tokens
-
+
Access Tokens
See the{' '}
-
documentation for Boost Note for Teams API{' '}
-
+
- setTokenCreateMode(!tokenCreateMode)}
disabled={apiTokenState.state === 'initialising'}
>
{tokenCreateMode ? 'Close' : 'Generate Token'}
-
+
{tokenCreateMode && (
diff --git a/src/cloud/components/organisms/settings/IntegrationsTab.tsx b/src/cloud/components/organisms/settings/IntegrationsTab.tsx
index 4fed1d3842..fff4ff0312 100644
--- a/src/cloud/components/organisms/settings/IntegrationsTab.tsx
+++ b/src/cloud/components/organisms/settings/IntegrationsTab.tsx
@@ -1,7 +1,5 @@
import React, { useCallback, useMemo } from 'react'
import styled from '../../../lib/styled'
-import { SectionSubtleText, SectionHeader2 } from './styled'
-import CustomButton from '../../atoms/buttons/CustomButton'
import ServiceConnect from '../../atoms/ServiceConnect'
import Spinner from '../../atoms/CustomSpinner'
import {
@@ -13,11 +11,11 @@ import { MixpanelActionTrackTypes } from '../../../interfaces/analytics/mixpanel
import FeedbackModal from '../Modal/contents/FeedbackModal'
import { githubOauthId, boostHubBaseUrl } from '../../../lib/consts'
import { usingElectron } from '../../../lib/stores/electron'
-import Button from '../../atoms/Button'
import { openNew } from '../../../lib/utils/platform'
import { usePage } from '../../../lib/stores/pageStore'
import { useModal } from '../../../../shared/lib/stores/modal'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
+import Button from '../../../../shared/components/atoms/Button'
const IntegrationsTab = () => {
const { openModal } = useModal()
@@ -46,9 +44,9 @@ const IntegrationsTab = () => {
body={
<>
-
+
Connect 3rd party content to your Boost Note for Teams documents.
-
+
@@ -60,19 +58,19 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
-
onIntegrationLinkClick('global')}
>
See
-
+
- Popular Integrations
+ Popular Integrations
@@ -90,13 +88,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
-
onIntegrationLinkClick('github')}
>
See
-
+
@@ -115,13 +113,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('trello')}
>
See
-
+
@@ -140,13 +138,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('slack')}
>
See
-
+
@@ -165,13 +163,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('gmail')}
>
See
-
+
@@ -193,13 +191,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('google-calendar')}
>
See
-
+
@@ -221,13 +219,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('google-drive')}
>
See
-
+
@@ -246,13 +244,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('jira')}
>
See
-
+
@@ -271,13 +269,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('miro')}
>
See
-
+
@@ -296,13 +294,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('dropbox')}
>
See
-
+
@@ -321,13 +319,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('airtable')}
>
See
-
+
@@ -346,13 +344,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('clickup')}
>
See
-
+
@@ -375,13 +373,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('lambda')}
>
See
-
+
@@ -400,13 +398,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('mailchimp')}
>
See
-
+
@@ -425,13 +423,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('intercom')}
>
See
-
+
@@ -451,13 +449,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('stripe')}
>
See
-
+
@@ -473,13 +471,13 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('asana')}
>
See
-
+
@@ -492,19 +490,19 @@ const IntegrationsTab = () => {
target='_blank'
rel='noreferrer noopener'
>
- onIntegrationLinkClick('zapier')}
>
See
-
+
- External Entity
+ External Entity
@@ -528,12 +526,9 @@ const IntegrationsTab = () => {
{(connectionState.type === 'initialising' ||
connectionState.type === 'working') && (
-
+
-
+
)}
{connectionState.type === 'initialised' && (
<>
@@ -549,7 +544,7 @@ const IntegrationsTab = () => {
) : (
{
)
) : (
-
Disable
-
+
)}
>
)}
diff --git a/src/cloud/components/organisms/settings/MembersTab.tsx b/src/cloud/components/organisms/settings/MembersTab.tsx
index 2c45836450..a807d53665 100644
--- a/src/cloud/components/organisms/settings/MembersTab.tsx
+++ b/src/cloud/components/organisms/settings/MembersTab.tsx
@@ -1,11 +1,4 @@
import React, { useCallback, useState, useEffect, useRef } from 'react'
-import {
- SectionHeader2,
- StyledMembername,
- SectionSelect,
- SectionDescription,
- PrimaryAnchor,
-} from './styled'
import { useTranslation } from 'react-i18next'
import { usePage } from '../../../lib/stores/pageStore'
import {
@@ -37,7 +30,6 @@ import { mdiArrowRight, mdiCardTextOutline, mdiChevronDown } from '@mdi/js'
import { deleteGuestDoc, getGuestsEmails } from '../../../api/guests'
import { useSet } from 'react-use'
import plur from 'plur'
-import Button from '../../atoms/Button'
import {
MenuTypes,
useContextMenu,
@@ -49,6 +41,9 @@ import SettingsTeamForm from '../../molecules/SettingsTeamForm'
import { guestsPerMember } from '../../../lib/subscription'
import { useToast } from '../../../../shared/lib/stores/toast'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
+import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
+import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
+import Button from '../../../../shared/components/atoms/Button'
const MembersTab = () => {
const { t } = useTranslation()
@@ -376,7 +371,7 @@ const MembersTab = () => {
{doc != null ? getDocTitle(doc, 'Untitled') : 'Untitled'}
removeGuestAccess(guest.id, docId)}
size='sm'
disabled={has(guest.id)}
@@ -427,28 +422,30 @@ const MembersTab = () => {
return (
+ setTab('member')}
+ >
+ Members ({permissions.length})
+
+ setTab('guest')}
+ >
+ Guests ({guestsMap.size})
+
+
+ }
+ description={'Manage who access to this space.'}
body={
<>
-
- setTab('member')}
- >
- Members ({permissions.length})
-
- setTab('guest')}
- >
- Guests ({guestsMap.size})
-
-
-
{tab === 'member' ? (
team.personal ? (
- Current Members
+ Current Members
{fetching.has('userEmails') && (
)}
@@ -496,7 +493,7 @@ const MembersTab = () => {
- Current Members
+ Current Members
{fetching.has('userEmails') && (
)}
@@ -541,7 +538,7 @@ const MembersTab = () => {
}}
/>
) : (
-
changePermissionsRole(
@@ -560,10 +557,13 @@ const MembersTab = () => {
!currentUserIsAdmin ||
targetPermissionsAreUsersOwn
}
- >
- admin
- member
-
+ options={
+ <>
+ admin
+ member
+ >
+ }
+ >
)}
{(targetPermissionsAreUsersOwn ||
currentUserIsAdmin) && (
@@ -600,43 +600,43 @@ const MembersTab = () => {
{subscription == null || subscription.status === 'inactive' ? (
<>
-
+
Upgrade to invite guests. Guests are people external to
your team who you want to work with on specific documents.
They can be invited to individual documents but not an
entire workspace.
{` `}
-
See how it works
-
-
+
+
- {
openSettingsTab('teamUpgrade')
}}
>
Start Free Trial
-
+
>
) : (
- Current Guests
+ Current Guests
{fetching.has('guestEmails') && (
)}
-
+
Guests are people external to your team who you want to work
with on specific documents. They can be invited to
individual documents but not an entire workspace.
-
+
{permissions.length > 0
? `${
@@ -787,4 +787,23 @@ const StyledGuestInactiveText = styled.p`
margin-bottom: ${({ theme }) => theme.space.default}px;
`
+const StyledMembername = styled.div`
+ display: flex;
+ align-items: center;
+ flex: 1 1 auto;
+
+ p {
+ margin: 0;
+ color: ${({ theme }) => theme.baseTextColor};
+ padding-right: ${({ theme }) => theme.space.xsmall}px;
+ }
+
+ span {
+ color: ${({ theme }) => theme.subtleTextColor};
+ margin-left: ${({ theme }) => theme.space.xsmall}px;
+ font-size: ${({ theme }) => theme.fontSizes.small}px;
+ padding: 2px 5px;
+ }
+`
+
export default MembersTab
diff --git a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
index bdf2fb4c42..1d1048f424 100644
--- a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
@@ -15,6 +15,7 @@ import SettingTabContent from '../../../../shared/components/organisms/Settings/
import SettingInput from '../../../../shared/components/organisms/Settings/atoms/SettingInput'
import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
import Button from '../../../../shared/components/atoms/Button'
+import SettingDivider from '../../../../shared/components/organisms/Settings/atoms/SettingDivider'
const PersonalInfoTab = () => {
const {
@@ -183,8 +184,9 @@ const PersonalInfoTab = () => {
}
footer={
<>
+
{t('settings.account.delete')}
-
+
You may delete your account at any time, note that this is
unrecoverable.{' '}
diff --git a/src/cloud/components/organisms/settings/PreferencesTab.tsx b/src/cloud/components/organisms/settings/PreferencesTab.tsx
index 6214e43e7f..2c4c6757df 100644
--- a/src/cloud/components/organisms/settings/PreferencesTab.tsx
+++ b/src/cloud/components/organisms/settings/PreferencesTab.tsx
@@ -9,6 +9,7 @@ const PreferencesTab = () => {
return (
}
>
)
diff --git a/src/cloud/components/organisms/settings/SubscriptionTab.tsx b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
index 21b5335666..b431ffa3fd 100644
--- a/src/cloud/components/organisms/settings/SubscriptionTab.tsx
+++ b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
@@ -1,6 +1,5 @@
import React, { useCallback, useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
-import { StyledSmallFont } from './styled'
import { usePage } from '../../../lib/stores/pageStore'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import { Elements } from '@stripe/react-stripe-js'
@@ -82,7 +81,7 @@ const SubscriptionTab = () => {
title={t('settings.teamSubscription')}
body={
-
+
{formtab == null ? (
{
) : null}
)}
-
+
}
>
diff --git a/src/cloud/components/organisms/settings/TeamInfoTab.tsx b/src/cloud/components/organisms/settings/TeamInfoTab.tsx
index bf85753816..70ee2670c4 100644
--- a/src/cloud/components/organisms/settings/TeamInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/TeamInfoTab.tsx
@@ -1,5 +1,4 @@
import React, { useMemo } from 'react'
-import { SectionDescription, SectionSeparator } from './styled'
import { usePage } from '../../../lib/stores/pageStore'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import { useTranslation } from 'react-i18next'
@@ -7,6 +6,7 @@ import { useSettings } from '../../../lib/stores/settings'
import TeamLink from '../../atoms/Link/TeamLink'
import SettingsTeamForm from '../../molecules/SettingsTeamForm'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
+import SettingDivider from '../../../../shared/components/organisms/Settings/atoms/SettingDivider'
const TeamInfoTab = () => {
const { team, currentUserPermissions } = usePage()
@@ -25,11 +25,10 @@ const TeamInfoTab = () => {
return (
<>
-
+
- Space Deletion
-
-
+ Delete Space
+
Once you delete this space we will remove all associated data. There
is no turning back.{' '}
{
>
{t('general.delete')}
-
+
>
)
@@ -52,12 +51,13 @@ const TeamInfoTab = () => {
return (
- {adminContent}
}
+ footer={adminContent}
>
)
}
diff --git a/src/cloud/components/organisms/settings/UpgradeTab.tsx b/src/cloud/components/organisms/settings/UpgradeTab.tsx
index d72cbfdc7c..ef38f5faab 100644
--- a/src/cloud/components/organisms/settings/UpgradeTab.tsx
+++ b/src/cloud/components/organisms/settings/UpgradeTab.tsx
@@ -1,6 +1,6 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
-import { SectionRow, StyledSmallFont } from './styled'
+import { SectionRow } from './styled'
import { usePage } from '../../../lib/stores/pageStore'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import { Elements } from '@stripe/react-stripe-js'
@@ -77,6 +77,7 @@ const UpgradeTab = () => {
return (
{showTrialPopup && (
@@ -86,7 +87,7 @@ const UpgradeTab = () => {
/>
)}
>
}
@@ -121,7 +122,7 @@ const UpgradeTab = () => {
title={t('settings.teamUpgrade')}
body={
-
+
{currentUserPermissions.role !== 'admin' ? (
Only admins can access this content.
@@ -144,7 +145,7 @@ const UpgradeTab = () => {
)
)}
-
+
}
>
diff --git a/src/cloud/components/organisms/settings/UserPreferencesForm.tsx b/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
index 5ad08d424e..33f4c1be46 100644
--- a/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
+++ b/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
@@ -1,5 +1,4 @@
import React, { useCallback } from 'react'
-import { SectionSelect, SectionHeader3 } from './styled'
import {
useSettings,
GeneralThemeOptions,
@@ -14,6 +13,7 @@ import { useTranslation } from 'react-i18next'
import { SelectChangeEventHandler } from '../../../lib/utils/events'
import { trackEvent } from '../../../api/track'
import { MixpanelActionTrackTypes } from '../../../interfaces/analytics/mixpanel'
+import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
const UserPreferencesForm = () => {
const { settings, setSettings } = useSettings()
@@ -88,64 +88,101 @@ const UserPreferencesForm = () => {
)
return (
-
- {t('settings.applicationTheme')}
-
- {t('settings.light')}
- {t('settings.dark')}
-
+ <>
+
+
+ {t('settings.light')}
+ {t('settings.dark')}
+ >
+ }
+ >
+
- {t('settings.editorTheme')}
-
- {codeMirrorEditorThemes.map((val) => (
-
- {val}
-
- ))}
-
- {t('settings.codeblockTheme')}
-
- {codeMirrorEditorThemes.map((val) => (
-
- {val}
-
- ))}
-
- {t('settings.editorKeyMap')}
-
- {codeMirrorKeyMap.map((val) => (
-
- {val}
-
- ))}
-
- Editor Indent Type
-
- Spaces
- Tab
-
- Editor Indent Size
-
- 8
- 4
- 2
-
-
+
+
+ {codeMirrorEditorThemes.map((val) => (
+
+ {val}
+
+ ))}
+ >
+ }
+ >
+
+
+
+
+ {codeMirrorEditorThemes.map((val) => (
+
+ {val}
+
+ ))}
+ >
+ }
+ >
+
+
+
+
+ {codeMirrorKeyMap.map((val) => (
+
+ {val}
+
+ ))}
+ >
+ }
+ >
+
+
+
+
+ Spaces
+ Tab
+ >
+ }
+ >
+
+
+
+
+ 8
+ 4
+ 2
+ >
+ }
+ >
+
+ >
)
}
diff --git a/src/cloud/components/organisms/settings/styled.ts b/src/cloud/components/organisms/settings/styled.ts
index 5e1d521fe8..d60d4fbb0c 100644
--- a/src/cloud/components/organisms/settings/styled.ts
+++ b/src/cloud/components/organisms/settings/styled.ts
@@ -1,91 +1,5 @@
import styled from '../../../lib/styled'
-import {
- selectStyle,
- primaryButtonStyle,
- secondaryButtonStyle,
- inputStyle,
- baseIconStyle,
- baseButtonStyle,
-} from '../../../lib/styled/styleFunctions'
-
-export const Section = styled.section`
- padding: ${({ theme }) => theme.space.xsmall}px 0;
-`
-
-export const SectionHeader2 = styled.h2`
- margin: ${({ theme }) => theme.space.medium}px 0
- ${({ theme }) => theme.space.default}px;
- font-size: ${({ theme }) => theme.fontSizes.default}px;
- font-weight: 500;
-`
-
-export const SectionHeader3 = styled.h3`
- display: inline-block;
- width: 40%;
- margin: ${({ theme }) => theme.space.default}px 0;
- font-size: ${({ theme }) => theme.fontSizes.small}px;
- font-weight: 500;
-`
-
-export const SectionLabel = styled.label`
- display: inline-block;
- width: 40%;
- color: ${({ theme }) => theme.emphasizedTextColor};
- font-size: ${({ theme }) => theme.fontSizes.small}px;
-`
-
-export const SectionParagraph = styled.div`
- display: block;
- color: ${({ theme }) => theme.emphasizedTextColor};
- font-size: ${({ theme }) => theme.fontSizes.default}px;
-`
-
-export const SectionSubtleText = styled.p`
- color: ${({ theme }) => theme.subtleTextColor};
-`
-
-export const PrimaryAnchor = styled.a`
- color: ${({ theme }) => theme.primaryBackgroundColor};
- text-decoration: none;
- &:hover {
- color: ${({ theme }) => theme.darkerPrimaryBackgroundColor};
- text-decoration: underline;
- }
-`
-
-export const SectionSelect = styled.select`
- ${selectStyle}
- min-width: 200px;
- width: 60%;
- height: 40px;
- padding: 0 ${({ theme }) => theme.space.small}px;
- border-radius: 2px;
-
- option {
- color: initial;
- }
-`
-
-export const SectionPrimaryButton = styled.button`
- ${baseButtonStyle}
- ${primaryButtonStyle}
- vertical-align: middle;
- align-items: center;
-
- svg.icon {
- position: relative;
- color: ${({ theme }) => theme.whiteTextColor};
- transform: none;
- top: 0;
- left: 0;
- }
-`
-
-export const SectionSecondaryButton = styled.button`
- ${baseButtonStyle}
- ${secondaryButtonStyle}
- align-items: center;
-`
+import { baseIconStyle } from '../../../lib/styled/styleFunctions'
export const SectionList = styled.ul`
margin: 0;
@@ -129,44 +43,6 @@ export const SectionInLineIcon = styled.span`
${baseIconStyle}
`
-export const SectionInput = styled.input`
- ${inputStyle}
- flex-grow: 1;
- flex-shrink: 1;
- min-width: 200px;
- width: 60%;
- height: 40px;
- padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.small}px;
- border-radius: 2px;
-`
-
-export const SectionTextarea = styled.textarea`
- ${inputStyle}
- flex-grow: 1;
- flex-shrink: 1;
- min-width: 200px;
- width: 100%;
- height: 200px;
- padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.small}px;
- border-radius: 2px;
- resize: none;
-`
-
-export const SectionProfilePic = styled.div`
- margin-top: ${({ theme }) => theme.space.default}px;
-`
-
-export const SectionFooter = styled.div`
- flex-grow: 0;
- flex-shrink: 0;
- padding: ${({ theme }) => theme.space.small}px
- ${({ theme }) => theme.space.default}px;
- border-top: 1px solid ${({ theme }) => theme.baseBorderColor};
- text-align: center;
-`
-
export const SectionIntroduction = styled.div`
.setHeight {
display: block;
@@ -218,10 +94,6 @@ export const SectionFlexRow = styled.div`
}
`
-export const StyledSmallFont = styled.div`
- font-size: ${({ theme }) => theme.fontSizes.small}px;
-`
-
export const SectionFlexDualButtons = styled.div`
display: flex;
align-items: center;
@@ -242,42 +114,3 @@ export const SectionFlexDualButtons = styled.div`
}
}
`
-
-export const SectionDescription = styled.small`
- color: ${({ theme }) => theme.subtleTextColor};
- display: block;
- margin-bottom: ${({ theme }) => theme.space.xsmall}px;
- line-height: 1.6;
-`
-
-export const SectionFlexLeft = styled.div`
- display: flex;
- justify-content: flex-start;
- margin: ${({ theme }) => theme.space.medium}px 0;
-`
-
-export const SectionSeparator = styled.div`
- background-color: ${({ theme }) => theme.baseBorderColor};
- width: 100%;
- margin: 120px 0 40px 0;
- height: 1px;
-`
-
-export const StyledMembername = styled.div`
- display: flex;
- align-items: center;
- flex: 1 1 auto;
-
- p {
- margin: 0;
- color: ${({ theme }) => theme.baseTextColor};
- padding-right: ${({ theme }) => theme.space.xsmall}px;
- }
-
- span {
- color: ${({ theme }) => theme.subtleTextColor};
- margin-left: ${({ theme }) => theme.space.xsmall}px;
- font-size: ${({ theme }) => theme.fontSizes.small}px;
- padding: 2px 5px;
- }
-`
From d51e7ab2a2048025fe585afcb9ebc06dd509f333 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 18:52:26 +0900
Subject: [PATCH 39/91] Added placeholder
---
src/shared/components/organisms/Settings/atoms/SettingInput.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/shared/components/organisms/Settings/atoms/SettingInput.tsx b/src/shared/components/organisms/Settings/atoms/SettingInput.tsx
index 3ebb720239..1bcd2decf0 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingInput.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingInput.tsx
@@ -4,6 +4,7 @@ import styled from '../../../../lib/styled'
interface SettingInputProps {
label?: string
value?: string
+ placeholder?: string
onChange?: React.ChangeEventHandler
}
From 83cabf507272cf685ad910b2660751e73f1b902e Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 18:52:54 +0900
Subject: [PATCH 40/91] Added value & style
---
.../components/organisms/Settings/atoms/SettingSelect.tsx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx b/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
index 408d7c87b7..7123519e7c 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
@@ -3,9 +3,10 @@ import styled from '../../../../lib/styled'
interface SettingSelectProps {
label?: string
- value?: string
+ value?: string | number
disabled?: boolean
onChange?: (val: any) => void
+ style?: React.CSSProperties
options: React.ReactNode
}
From ef43ab349c3445bdae20e187b8fa5576c4fdfe72 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sun, 9 May 2021 19:21:22 +0900
Subject: [PATCH 41/91] Adjusted Modal z-index
---
src/shared/components/organisms/Settings/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/components/organisms/Settings/index.tsx b/src/shared/components/organisms/Settings/index.tsx
index cb44067480..bc6125bc76 100644
--- a/src/shared/components/organisms/Settings/index.tsx
+++ b/src/shared/components/organisms/Settings/index.tsx
@@ -16,7 +16,7 @@ const Settings = ({ sidebar, content }: SettingsProps) => (
)
-const zIndexModals = 8001
+const zIndexModals = 8000
const Container = styled.div`
z-index: ${zIndexModals};
From f435c8e2de81a306b9dee0b457d052c772b17a20 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 13:13:27 +0900
Subject: [PATCH 42/91] EmphasizedLink -> SettingLink
---
src/cloud/components/atoms/Link/AccountLink.tsx | 6 +++---
.../components/atoms/Link/EmphasizedLink.tsx | 15 ---------------
src/cloud/components/atoms/Link/TeamLink.tsx | 6 +++---
.../organisms/Settings/atoms/SettingLink.tsx | 16 ++++++++++------
4 files changed, 16 insertions(+), 27 deletions(-)
delete mode 100644 src/cloud/components/atoms/Link/EmphasizedLink.tsx
diff --git a/src/cloud/components/atoms/Link/AccountLink.tsx b/src/cloud/components/atoms/Link/AccountLink.tsx
index bf8858a018..94212d4282 100644
--- a/src/cloud/components/atoms/Link/AccountLink.tsx
+++ b/src/cloud/components/atoms/Link/AccountLink.tsx
@@ -1,6 +1,6 @@
import React, { FC } from 'react'
import querystring from 'querystring'
-import EmphasizedLink from './EmphasizedLink'
+import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
export type AccountLinkIntent = 'delete'
@@ -23,7 +23,7 @@ const AccountLink: FC = ({
beforeNavigate,
}) => {
return (
- = ({
draggable={draggable}
>
{children}
-
+
)
}
diff --git a/src/cloud/components/atoms/Link/EmphasizedLink.tsx b/src/cloud/components/atoms/Link/EmphasizedLink.tsx
deleted file mode 100644
index 7f2c4ba992..0000000000
--- a/src/cloud/components/atoms/Link/EmphasizedLink.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import styled from '../../../lib/styled'
-import Link from './Link'
-
-const EmphasizedLink = styled(Link)`
- a {
- color: ${({ theme }) => theme.primaryTextColor};
-
- &:hover,
- &:focus {
- text-decoration: none;
- }
- }
-`
-
-export default EmphasizedLink
diff --git a/src/cloud/components/atoms/Link/TeamLink.tsx b/src/cloud/components/atoms/Link/TeamLink.tsx
index 5703950545..1d326b0596 100644
--- a/src/cloud/components/atoms/Link/TeamLink.tsx
+++ b/src/cloud/components/atoms/Link/TeamLink.tsx
@@ -2,7 +2,7 @@ import React, { useCallback } from 'react'
import querystring from 'querystring'
import { SerializedTeam } from '../../../interfaces/db/team'
import { useRouter } from '../../../lib/router'
-import EmphasizedLink from './EmphasizedLink'
+import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
export type TeamLinkIntent =
| 'index'
@@ -47,7 +47,7 @@ const TeamLink = ({
tabIndex = 0,
}: TeamLinkProps) => {
return (
-
{children}
-
+
)
}
diff --git a/src/shared/components/organisms/Settings/atoms/SettingLink.tsx b/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
index 489a2eae99..f7533cc382 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
@@ -1,12 +1,16 @@
import styled from '../../../../lib/styled'
+import Link from '../../../atoms/Link'
-const SettingLink = styled.a`
- color: ${({ theme }) => theme.colors.text.link};
- text-decoration: none;
-
- &:hover {
+const SettingLink = styled(Link)`
+ a {
color: ${({ theme }) => theme.colors.text.link};
- text-decoration: underline;
+ text-decoration: none;
+
+ &:hover,
+ &:focus {
+ color: ${({ theme }) => theme.colors.text.link};
+ text-decoration: underline;
+ }
}
`
From db32a659754b6af359f95d9350c4f72328cf23c2 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 13:42:09 +0900
Subject: [PATCH 43/91] IconInput -> SettingIconInput
---
src/cloud/components/molecules/IconInput.tsx | 94 --------------------
1 file changed, 94 deletions(-)
delete mode 100644 src/cloud/components/molecules/IconInput.tsx
diff --git a/src/cloud/components/molecules/IconInput.tsx b/src/cloud/components/molecules/IconInput.tsx
deleted file mode 100644
index 2c2fa58daf..0000000000
--- a/src/cloud/components/molecules/IconInput.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import React, { useState, useCallback } from 'react'
-import styled from '../../lib/styled'
-import {
- secondaryButtonStyle,
- baseButtonStyle,
-} from '../../lib/styled/styleFunctions'
-
-interface IconInputProps {
- onChange?: (file: File) => void
- defaultUrl?: string
- shape?: 'square' | 'circle'
-}
-
-const IconInput = ({
- onChange,
- defaultUrl,
- shape = 'square',
-}: IconInputProps) => {
- const [fileUrl, setFileUrl] = useState(null)
-
- const changeHandler: React.ChangeEventHandler = useCallback(
- (event) => {
- if (
- event.target != null &&
- event.target.files != null &&
- event.target.files.length > 0
- ) {
- const file = event.target.files[0]
- setFileUrl(URL.createObjectURL(file))
- if (onChange != null) {
- onChange(file)
- }
- }
- },
- [onChange]
- )
-
- return (
-
-
-
-
-
- Select Image...
-
-
-
- )
-}
-
-export default IconInput
-
-const StyledIcon = styled.div`
- display: flex;
- align-items: center;
-`
-
-const StyledIconImage = styled.div`
- width: 90px;
- height: 90px;
-`
-
-const StyledIconImageContent = styled.img<{ shape: string }>`
- object-fit: cover;
- width: 100%;
- height: 100%;
- background: ${({ theme }) => theme.secondaryBackgroundColor};
- border: 1px solid ${({ theme }) => theme.secondaryBorderColor};
- border-radius: ${(props: any) => (props.shape === 'circle' ? '100%' : '0')};
-`
-
-const StyledIconInputLabel = styled.label`
- position: relative;
- cursor: pointer;
- margin-left: ${({ theme }) => theme.space.default}px;
-
- & > span {
- display: block;
- padding: 8px 16px;
- border-radius: 5px;
- ${baseButtonStyle}
- ${secondaryButtonStyle}
- }
-
- & > input[type='file'] {
- position: absolute;
- opacity: 0;
- height: 0px;
- width: 0px;
- }
-`
From 105b2ffb9cfccc4dbbd62639d245dba5620f97c2 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 13:42:32 +0900
Subject: [PATCH 44/91] IconInput -> SettingIconInput
---
.../organisms/settings/PersonalInfoTab.tsx | 8 +-
.../Settings/atoms/SettingIconInput.tsx | 100 ++++++++++++++++++
2 files changed, 102 insertions(+), 6 deletions(-)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingIconInput.tsx
diff --git a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
index 1d1048f424..4790229c4c 100644
--- a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
@@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next'
import { useGlobalData } from '../../../lib/stores/globalData'
import { saveUserInfo, updateUserIcon } from '../../../api/users'
import { buildIconUrl } from '../../../api/files'
-import IconInput from '../../molecules/IconInput'
import { Spinner } from '../../atoms/Spinner'
import { useSettings } from '../../../lib/stores/settings'
import AccountLink from '../../atoms/Link/AccountLink'
@@ -16,6 +15,7 @@ import SettingInput from '../../../../shared/components/organisms/Settings/atoms
import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
import Button from '../../../../shared/components/atoms/Button'
import SettingDivider from '../../../../shared/components/organisms/Settings/atoms/SettingDivider'
+import SettingIconInput from '../../../../shared/components/organisms/Settings/atoms/SettingIconInput'
const PersonalInfoTab = () => {
const {
@@ -118,11 +118,7 @@ const PersonalInfoTab = () => {
{currentUser != null && (
<>
void
+ defaultUrl?: string
+}
+
+const SettingIconInput = ({ onChange, defaultUrl }: SettingIconInputProps) => {
+ const [fileUrl, setFileUrl] = useState(null)
+
+ const changeHandler: React.ChangeEventHandler = useCallback(
+ (event) => {
+ if (
+ event.target != null &&
+ event.target.files != null &&
+ event.target.files.length > 0
+ ) {
+ const file = event.target.files[0]
+ setFileUrl(URL.createObjectURL(file))
+ if (onChange != null) {
+ onChange(file)
+ }
+ }
+ },
+ [onChange]
+ )
+
+ return (
+
+
+
+
+
+ Select Image...
+
+
+
+ )
+}
+
+export default SettingIconInput
+
+const Container = styled.div`
+ display: flex;
+ align-items: center;
+
+ .setting__icon-input__img {
+ width: 90px;
+ height: 90px;
+ }
+
+ .setting__icon-input__img__content {
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
+ background: ${({ theme }) => theme.colors.background.secondary};
+ border: 1px solid ${({ theme }) => theme.colors.border.second};
+ border-radius: 50%;
+ }
+
+ .setting__icon-input__label {
+ position: relative;
+ cursor: pointer;
+ margin-left: ${({ theme }) => theme.sizes.spaces.df}px;
+
+ & > span {
+ display: flex;
+ align-items: center;
+ height: 32px;
+ padding: 0 ${({ theme }) => theme.sizes.spaces.md}px;
+ background-color: ${({ theme }) => theme.colors.variants.secondary.base};
+ border-radius: 4px;
+ color: ${({ theme }) => theme.colors.variants.secondary.text};
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+ transition: 200ms background-color;
+
+ &.focus {
+ filter: brightness(103%);
+ }
+ &:hover {
+ filter: brightness(106%);
+ }
+ &:active,
+ &.button__state--active {
+ filter: brightness(112%);
+ }
+ }
+
+ & > input[type='file'] {
+ position: absolute;
+ opacity: 0;
+ height: 0px;
+ width: 0px;
+ }
+ }
+`
From fbf3bedb49bd545421543d7a65192cb365bc34e9 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 13:43:00 +0900
Subject: [PATCH 45/91] Removed Unnecessary Styles
---
src/shared/components/atoms/Button.tsx | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/shared/components/atoms/Button.tsx b/src/shared/components/atoms/Button.tsx
index d912e43fca..2d497a758c 100644
--- a/src/shared/components/atoms/Button.tsx
+++ b/src/shared/components/atoms/Button.tsx
@@ -144,7 +144,6 @@ export default Button
const StyledButton = styled.button`
padding: 0 ${({ theme }) => theme.sizes.spaces.md}px;
- border-radius: 2px;
font-size: ${({ theme }) => theme.sizes.fonts.df}px;
height: 32px;
outline: none;
@@ -157,7 +156,6 @@ const StyledButton = styled.button`
display: inline-flex;
align-items: center;
justify-content: center;
- font-family: Arial;
box-sizing: border-box;
transition: 200ms background-color;
width: auto;
From d805a9fcf59447cd1e87d5f4efeeaf84333eb642 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 13:49:03 +0900
Subject: [PATCH 46/91] Removed {}
---
src/cloud/components/organisms/settings/ApiTab.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/cloud/components/organisms/settings/ApiTab.tsx b/src/cloud/components/organisms/settings/ApiTab.tsx
index 9d5ba08a9a..a256b351d7 100644
--- a/src/cloud/components/organisms/settings/ApiTab.tsx
+++ b/src/cloud/components/organisms/settings/ApiTab.tsx
@@ -35,8 +35,8 @@ const ApiTab = () => {
return (
From 97299560091c669a8234f6c9059de949d9fd707d Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 13:49:23 +0900
Subject: [PATCH 47/91] Put subtle text to description
---
src/cloud/components/organisms/settings/IntegrationsTab.tsx | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/cloud/components/organisms/settings/IntegrationsTab.tsx b/src/cloud/components/organisms/settings/IntegrationsTab.tsx
index fff4ff0312..57162342d5 100644
--- a/src/cloud/components/organisms/settings/IntegrationsTab.tsx
+++ b/src/cloud/components/organisms/settings/IntegrationsTab.tsx
@@ -40,13 +40,11 @@ const IntegrationsTab = () => {
return (
-
- Connect 3rd party content to your Boost Note for Teams documents.
-
From 45074a33d91e3798f60e0d234191eb3a3e4e7965 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 14:08:36 +0900
Subject: [PATCH 48/91] TokenCreate -> SettingTokenCreate
---
.../components/molecules/TokenCreate.tsx | 51 -------------------
.../components/organisms/settings/ApiTab.tsx | 6 +--
.../Settings/atoms/SettingTokenCreate.tsx | 49 ++++++++++++++++++
3 files changed, 52 insertions(+), 54 deletions(-)
delete mode 100644 src/cloud/components/molecules/TokenCreate.tsx
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx
diff --git a/src/cloud/components/molecules/TokenCreate.tsx b/src/cloud/components/molecules/TokenCreate.tsx
deleted file mode 100644
index 134b7488cf..0000000000
--- a/src/cloud/components/molecules/TokenCreate.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React, { useState, useCallback, ChangeEvent } from 'react'
-import CustomButton from '../atoms/buttons/CustomButton'
-import Flexbox from '../atoms/Flexbox'
-import styled from '../../lib/styled'
-import SettingInput from '../../../shared/components/organisms/Settings/atoms/SettingInput'
-
-interface TokenCreateProps {
- onCreate: (name: string) => void
-}
-
-const TokenCreate = ({ onCreate }: TokenCreateProps) => {
- const [name, setName] = useState('')
-
- const create = useCallback(() => {
- onCreate(name)
- }, [name, onCreate])
-
- return (
-
- Create a token
-
- ) =>
- setName(e.target.value)
- }
- >
-
-
- {name.length === 0 && (
- Enter a name
- )}
-
- Create
-
-
-
- )
-}
-
-export default TokenCreate
-
-const StyledTokenCreate = styled.div`
- width: 100%;
-`
-
-const StyledWarningText = styled.small`
- margin-right: ${({ theme }) => theme.space.xsmall}px;
- color: ${({ theme }) => theme.warningTextColor};
-`
diff --git a/src/cloud/components/organisms/settings/ApiTab.tsx b/src/cloud/components/organisms/settings/ApiTab.tsx
index a256b351d7..e9043217f6 100644
--- a/src/cloud/components/organisms/settings/ApiTab.tsx
+++ b/src/cloud/components/organisms/settings/ApiTab.tsx
@@ -3,14 +3,14 @@ import styled from '../../../lib/styled'
import Spinner from '../../atoms/CustomSpinner'
import { useApiTokens, withApiTokens } from '../../../lib/stores/apiTokens'
import TokenControl from '../../molecules/TokenControl'
-import TokenCreate from '../../molecules/TokenCreate'
import { usePage } from '../../../lib/stores/pageStore'
-import Flexbox from '../../atoms/Flexbox'
import Icon from '../../atoms/IconMdi'
import { mdiOpenInNew } from '@mdi/js'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
import Button from '../../../../shared/components/atoms/Button'
+import SettingTokenCreate from '../../../../shared/components/organisms/Settings/atoms/SettingTokenCreate'
+import Flexbox from '../../../../shared/components/atoms/Flexbox'
const ApiTab = () => {
const { team } = usePage()
@@ -70,7 +70,7 @@ const ApiTab = () => {
{tokenCreateMode && (
-
+
)}
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx b/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx
new file mode 100644
index 0000000000..9ae0a760d7
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx
@@ -0,0 +1,49 @@
+import React, { useState, useCallback, ChangeEvent } from 'react'
+import styled from '../../../../lib/styled'
+import Button from '../../../atoms/Button'
+import Flexbox from '../../../atoms/Flexbox'
+import SettingInput from './SettingInput'
+
+interface SettingTokenCreateProps {
+ onCreate: (name: string) => void
+}
+
+const SettingTokenCreate = ({ onCreate }: SettingTokenCreateProps) => {
+ const [name, setName] = useState('')
+
+ const create = useCallback(() => {
+ onCreate(name)
+ }, [name, onCreate])
+
+ return (
+
+ Create a token
+
+ ) =>
+ setName(e.target.value)
+ }
+ >
+
+
+ {name.length === 0 && Enter a name
}
+
+ Create
+
+
+
+ )
+}
+
+export default SettingTokenCreate
+
+const Container = styled.div`
+ width: 100%;
+
+ .text--warning {
+ margin-right: ${({ theme }) => theme.sizes.spaces.sm}px;
+ color: ${({ theme }) => theme.colors.variants.warning.base};
+ }
+`
From 6b8fc7897644d9582e73056d2ee2cb12a7bbbec1 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 14:08:59 +0900
Subject: [PATCH 49/91] Changed to Shared Component Flexbox
---
src/cloud/components/organisms/settings/MembersTab.tsx | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/src/cloud/components/organisms/settings/MembersTab.tsx b/src/cloud/components/organisms/settings/MembersTab.tsx
index a807d53665..d43daf8686 100644
--- a/src/cloud/components/organisms/settings/MembersTab.tsx
+++ b/src/cloud/components/organisms/settings/MembersTab.tsx
@@ -21,7 +21,6 @@ import UserIcon from '../../atoms/UserIcon'
import styled from '../../../lib/styled'
import { arraysAreIdentical } from '../../../lib/utils/array'
import { getUserEmailsFromPermissions } from '../../../api/teams/permissions/emails'
-import Flexbox from '../../atoms/Flexbox'
import { useRouter } from '../../../lib/router'
import cc from 'classcat'
import { useNav } from '../../../lib/stores/nav'
@@ -44,6 +43,7 @@ import SettingTabContent from '../../../../shared/components/organisms/Settings/
import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
import Button from '../../../../shared/components/atoms/Button'
+import Flexbox from '../../../../shared/components/atoms/Flexbox'
const MembersTab = () => {
const { t } = useTranslation()
@@ -354,11 +354,8 @@ const MembersTab = () => {
return {
type: MenuTypes.Component,
component: (
-
-
+
+
{doc != null ? (
Date: Mon, 10 May 2021 14:32:43 +0900
Subject: [PATCH 50/91] Adjusted Token Section Styles
---
src/cloud/components/molecules/TokenControl.tsx | 2 +-
.../components/organisms/Settings/atoms/SettingTokenCreate.tsx | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/cloud/components/molecules/TokenControl.tsx b/src/cloud/components/molecules/TokenControl.tsx
index 0a1752b264..f9dea18bca 100644
--- a/src/cloud/components/molecules/TokenControl.tsx
+++ b/src/cloud/components/molecules/TokenControl.tsx
@@ -81,7 +81,7 @@ const TokenControl = ({ token, onUpdate, onDelete }: TokenControlProps) => {
>
) : (
<>
- {name}
+ {name}
setEdit(true)}>
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx b/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx
index 9ae0a760d7..3b702494b4 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx
@@ -43,7 +43,8 @@ const Container = styled.div`
width: 100%;
.text--warning {
- margin-right: ${({ theme }) => theme.sizes.spaces.sm}px;
+ margin-top: 0;
+ margin-right: ${({ theme }) => theme.sizes.spaces.df}px;
color: ${({ theme }) => theme.colors.variants.warning.base};
}
`
From c0cfb7b0e0c6b3971a46d0acde052c0dd81dac4b Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 15:24:56 +0900
Subject: [PATCH 51/91] Added SettingTokenCreate
---
.../Settings/molecules/SettingTokenCreate.tsx | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 src/shared/components/organisms/Settings/molecules/SettingTokenCreate.tsx
diff --git a/src/shared/components/organisms/Settings/molecules/SettingTokenCreate.tsx b/src/shared/components/organisms/Settings/molecules/SettingTokenCreate.tsx
new file mode 100644
index 0000000000..666b07f918
--- /dev/null
+++ b/src/shared/components/organisms/Settings/molecules/SettingTokenCreate.tsx
@@ -0,0 +1,50 @@
+import React, { useState, useCallback, ChangeEvent } from 'react'
+import styled from '../../../../lib/styled'
+import Button from '../../../atoms/Button'
+import Flexbox from '../../../atoms/Flexbox'
+import SettingInput from '../atoms/SettingInput'
+
+interface SettingTokenCreateProps {
+ onCreate: (name: string) => void
+}
+
+const SettingTokenCreate = ({ onCreate }: SettingTokenCreateProps) => {
+ const [name, setName] = useState('')
+
+ const create = useCallback(() => {
+ onCreate(name)
+ }, [name, onCreate])
+
+ return (
+
+ Create a token
+
+ ) =>
+ setName(e.target.value)
+ }
+ >
+
+
+ {name.length === 0 && Enter a name
}
+
+ Create
+
+
+
+ )
+}
+
+export default SettingTokenCreate
+
+const Container = styled.div`
+ width: 100%;
+
+ .text--warning {
+ margin-top: 0;
+ margin-right: ${({ theme }) => theme.sizes.spaces.df}px;
+ color: ${({ theme }) => theme.colors.variants.warning.base};
+ }
+`
From 60d766164d6ca494101a585d430ed76ce56628a3 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 15:25:32 +0900
Subject: [PATCH 52/91] Moved Components
---
.../Settings/atoms/SettingTokenCreate.tsx | 50 -------------------
.../{atoms => molecules}/SettingIconInput.tsx | 41 ++-------------
.../SettingSidenavHeader.tsx | 0
3 files changed, 3 insertions(+), 88 deletions(-)
delete mode 100644 src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx
rename src/shared/components/organisms/Settings/{atoms => molecules}/SettingIconInput.tsx (62%)
rename src/shared/components/organisms/Settings/{atoms => molecules}/SettingSidenavHeader.tsx (100%)
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx b/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx
deleted file mode 100644
index 3b702494b4..0000000000
--- a/src/shared/components/organisms/Settings/atoms/SettingTokenCreate.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import React, { useState, useCallback, ChangeEvent } from 'react'
-import styled from '../../../../lib/styled'
-import Button from '../../../atoms/Button'
-import Flexbox from '../../../atoms/Flexbox'
-import SettingInput from './SettingInput'
-
-interface SettingTokenCreateProps {
- onCreate: (name: string) => void
-}
-
-const SettingTokenCreate = ({ onCreate }: SettingTokenCreateProps) => {
- const [name, setName] = useState('')
-
- const create = useCallback(() => {
- onCreate(name)
- }, [name, onCreate])
-
- return (
-
- Create a token
-
- ) =>
- setName(e.target.value)
- }
- >
-
-
- {name.length === 0 && Enter a name
}
-
- Create
-
-
-
- )
-}
-
-export default SettingTokenCreate
-
-const Container = styled.div`
- width: 100%;
-
- .text--warning {
- margin-top: 0;
- margin-right: ${({ theme }) => theme.sizes.spaces.df}px;
- color: ${({ theme }) => theme.colors.variants.warning.base};
- }
-`
diff --git a/src/shared/components/organisms/Settings/atoms/SettingIconInput.tsx b/src/shared/components/organisms/Settings/molecules/SettingIconInput.tsx
similarity index 62%
rename from src/shared/components/organisms/Settings/atoms/SettingIconInput.tsx
rename to src/shared/components/organisms/Settings/molecules/SettingIconInput.tsx
index 1a59ac50a8..cbf5f65798 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingIconInput.tsx
+++ b/src/shared/components/organisms/Settings/molecules/SettingIconInput.tsx
@@ -1,5 +1,6 @@
import React, { useState, useCallback } from 'react'
import styled from '../../../../lib/styled'
+import SettingIconInputLabel from '../atoms/SettingIconInputLabel'
interface SettingIconInputProps {
onChange?: (file: File) => void
@@ -34,10 +35,10 @@ const SettingIconInput = ({ onChange, defaultUrl }: SettingIconInputProps) => {
src={fileUrl != null ? fileUrl : defaultUrl}
/>
-
+
Select Image...
-
+
)
}
@@ -61,40 +62,4 @@ const Container = styled.div`
border: 1px solid ${({ theme }) => theme.colors.border.second};
border-radius: 50%;
}
-
- .setting__icon-input__label {
- position: relative;
- cursor: pointer;
- margin-left: ${({ theme }) => theme.sizes.spaces.df}px;
-
- & > span {
- display: flex;
- align-items: center;
- height: 32px;
- padding: 0 ${({ theme }) => theme.sizes.spaces.md}px;
- background-color: ${({ theme }) => theme.colors.variants.secondary.base};
- border-radius: 4px;
- color: ${({ theme }) => theme.colors.variants.secondary.text};
- font-size: ${({ theme }) => theme.sizes.fonts.df}px;
- transition: 200ms background-color;
-
- &.focus {
- filter: brightness(103%);
- }
- &:hover {
- filter: brightness(106%);
- }
- &:active,
- &.button__state--active {
- filter: brightness(112%);
- }
- }
-
- & > input[type='file'] {
- position: absolute;
- opacity: 0;
- height: 0px;
- width: 0px;
- }
- }
`
diff --git a/src/shared/components/organisms/Settings/atoms/SettingSidenavHeader.tsx b/src/shared/components/organisms/Settings/molecules/SettingSidenavHeader.tsx
similarity index 100%
rename from src/shared/components/organisms/Settings/atoms/SettingSidenavHeader.tsx
rename to src/shared/components/organisms/Settings/molecules/SettingSidenavHeader.tsx
From 9ec79eb072b49ec84eb61b1012ba01e111696237 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 15:25:57 +0900
Subject: [PATCH 53/91] Added SettingTabSelector
---
.../organisms/settings/MembersTab.tsx | 31 +++----------------
.../Settings/atoms/SettingTabSelector.tsx | 28 +++++++++++++++++
2 files changed, 32 insertions(+), 27 deletions(-)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingTabSelector.tsx
diff --git a/src/cloud/components/organisms/settings/MembersTab.tsx b/src/cloud/components/organisms/settings/MembersTab.tsx
index d43daf8686..90e65328df 100644
--- a/src/cloud/components/organisms/settings/MembersTab.tsx
+++ b/src/cloud/components/organisms/settings/MembersTab.tsx
@@ -44,6 +44,7 @@ import SettingSelect from '../../../../shared/components/organisms/Settings/atom
import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
import Button from '../../../../shared/components/atoms/Button'
import Flexbox from '../../../../shared/components/atoms/Flexbox'
+import SettingTabSelector from '../../../../shared/components/organisms/Settings/atoms/SettingTabSelector'
const MembersTab = () => {
const { t } = useTranslation()
@@ -420,7 +421,7 @@ const MembersTab = () => {
return (
+
setTab('member')}
@@ -433,7 +434,7 @@ const MembersTab = () => {
>
Guests ({guestsMap.size})
-
+
}
description={'Manage who access to this space.'}
body={
@@ -693,31 +694,6 @@ const MembersTab = () => {
)
}
-const TabSelector = styled.div`
- display: flex;
- button {
- background: transparent;
- margin-bottom: ${({ theme }) => theme.space.xxsmall}px;
- font-size: ${({ theme }) => theme.fontSizes.medium}px;
- color: ${({ theme }) => theme.subtleTextColor};
- border-bottom: 1px solid transparent;
- cursor: pointer;
- outline: none;
-
- &:hover {
- color: ${({ theme }) => theme.emphasizedTextColor};
- }
-
- &.active {
- color: ${({ theme }) => theme.emphasizedTextColor};
- border-color: ${({ theme }) => theme.emphasizedTextColor};
- }
- }
- button:first-of-type {
- margin-right: ${({ theme }) => theme.space.medium}px;
- }
-`
-
const TopMargin = styled.div`
margin-top: ${({ theme }) => theme.space.medium}px;
`
@@ -782,6 +758,7 @@ const StyledMembersTable = styled.table`
const StyledGuestInactiveText = styled.p`
margin-top: ${({ theme }) => theme.space.medium}px;
margin-bottom: ${({ theme }) => theme.space.default}px;
+ line-height: 1.6;
`
const StyledMembername = styled.div`
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabSelector.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabSelector.tsx
new file mode 100644
index 0000000000..5b2e57ea18
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabSelector.tsx
@@ -0,0 +1,28 @@
+import styled from '../../../../lib/styled'
+
+const SettingTabSelector = styled.div`
+ display: flex;
+
+ button {
+ padding: 0;
+ background: transparent;
+ color: ${({ theme }) => theme.colors.text.subtle};
+ cursor: pointer;
+ font-size: ${({ theme }) => theme.sizes.fonts.l}px;
+ outline: none;
+
+ &:hover {
+ color: ${({ theme }) => theme.colors.text.secondary};
+ }
+
+ &.active {
+ color: ${({ theme }) => theme.colors.text.primary};
+ }
+ }
+
+ button:first-of-type {
+ margin-right: ${({ theme }) => theme.sizes.spaces.xl}px;
+ }
+`
+
+export default SettingTabSelector
From 6edf82415b7579d794c3bb8a7f50063a20137b6e Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 15:26:28 +0900
Subject: [PATCH 54/91] Added SettingIconInputLabel
---
.../components/molecules/SettingsTeamForm.tsx | 47 +++++++------------
.../organisms/settings/PersonalInfoTab.tsx | 2 +-
.../Settings/atoms/SettingIconInputLabel.tsx | 39 +++++++++++++++
3 files changed, 58 insertions(+), 30 deletions(-)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingIconInputLabel.tsx
diff --git a/src/cloud/components/molecules/SettingsTeamForm.tsx b/src/cloud/components/molecules/SettingsTeamForm.tsx
index 2c60b270f5..61a0b61116 100644
--- a/src/cloud/components/molecules/SettingsTeamForm.tsx
+++ b/src/cloud/components/molecules/SettingsTeamForm.tsx
@@ -8,11 +8,6 @@ import { useElectron } from '../../lib/stores/electron'
import { useGlobalData } from '../../lib/stores/globalData'
import { usePage } from '../../lib/stores/pageStore'
import styled from '../../lib/styled'
-import {
- baseButtonStyle,
- inputStyle,
- inverseSecondaryButtonStyle,
-} from '../../lib/styled/styleFunctions'
import Flexbox from '../atoms/Flexbox'
import Icon from '../atoms/Icon'
import { Spinner } from '../atoms/Spinner'
@@ -20,6 +15,8 @@ import { useRouter } from '../../lib/router'
import { getTeamURL } from '../../lib/utils/patterns'
import { useToast } from '../../../shared/lib/stores/toast'
import Button from '../../../shared/components/atoms/Button'
+import SettingInput from '../../../shared/components/organisms/Settings/atoms/SettingInput'
+import SettingIconInputLabel from '../../../shared/components/organisms/Settings/atoms/SettingIconInputLabel'
interface SettingsTeamFormProps {
team: SerializedTeam
@@ -165,22 +162,24 @@ const SettingsTeamForm = ({
) : (
)}
+
+
+ {fileUrl == null ? 'Add a photo' : 'Change your photo'}
+
+
+
-
- {fileUrl == null ? 'Add a photo' : 'Change your photo'}
-
-
{label} name
- setName(ev.target.value)}
@@ -190,7 +189,7 @@ const SettingsTeamForm = ({
{label} domain
- setDomain(ev.target.value)}
@@ -234,12 +233,9 @@ const Container = styled.div`
color: ${({ theme }) => theme.secondaryBorderColor};
}
.profile__row {
+ display: flex;
+ align-items: center;
margin-bottom: ${({ theme }) => theme.space.small}px;
- text-align: center;
- }
- .profile__label {
- ${baseButtonStyle}
- ${inverseSecondaryButtonStyle}
}
#profile {
display: none;
@@ -271,13 +267,6 @@ const Container = styled.div`
margin: 0;
color: ${({ theme }) => theme.subtleTextColor};
}
- input[type='text'] {
- ${inputStyle};
- width: 100%;
- height: 30px;
- padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.small}px;
- }
.description {
font-size: ${({ theme }) => theme.fontSizes.xsmall}px;
margin-top: ${({ theme }) => theme.space.xsmall}px;
diff --git a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
index 4790229c4c..d38a025067 100644
--- a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
@@ -15,7 +15,7 @@ import SettingInput from '../../../../shared/components/organisms/Settings/atoms
import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
import Button from '../../../../shared/components/atoms/Button'
import SettingDivider from '../../../../shared/components/organisms/Settings/atoms/SettingDivider'
-import SettingIconInput from '../../../../shared/components/organisms/Settings/atoms/SettingIconInput'
+import SettingIconInput from '../../../../shared/components/organisms/Settings/molecules/SettingIconInput'
const PersonalInfoTab = () => {
const {
diff --git a/src/shared/components/organisms/Settings/atoms/SettingIconInputLabel.tsx b/src/shared/components/organisms/Settings/atoms/SettingIconInputLabel.tsx
new file mode 100644
index 0000000000..23913cd809
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingIconInputLabel.tsx
@@ -0,0 +1,39 @@
+import styled from '../../../../lib/styled'
+
+const SettingIconInputLabel = styled.label`
+ position: relative;
+ cursor: pointer;
+ margin-left: ${({ theme }) => theme.sizes.spaces.md}px;
+
+ & > span {
+ display: flex;
+ align-items: center;
+ height: 32px;
+ padding: 0 ${({ theme }) => theme.sizes.spaces.md}px;
+ background-color: ${({ theme }) => theme.colors.variants.secondary.base};
+ border-radius: 4px;
+ color: ${({ theme }) => theme.colors.variants.secondary.text};
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+ transition: 200ms background-color;
+
+ &.focus {
+ filter: brightness(103%);
+ }
+ &:hover {
+ filter: brightness(106%);
+ }
+ &:active,
+ &.button__state--active {
+ filter: brightness(112%);
+ }
+ }
+
+ & > input[type='file'] {
+ position: absolute;
+ opacity: 0;
+ height: 0px;
+ width: 0px;
+ }
+`
+
+export default SettingIconInputLabel
From e57a1faa6990e74db58e6a549f0a11aae571d56e Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 15:26:42 +0900
Subject: [PATCH 55/91] Added SettingTokenCreate
---
src/cloud/components/organisms/settings/ApiTab.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cloud/components/organisms/settings/ApiTab.tsx b/src/cloud/components/organisms/settings/ApiTab.tsx
index e9043217f6..a382d01b72 100644
--- a/src/cloud/components/organisms/settings/ApiTab.tsx
+++ b/src/cloud/components/organisms/settings/ApiTab.tsx
@@ -9,7 +9,7 @@ import { mdiOpenInNew } from '@mdi/js'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
import Button from '../../../../shared/components/atoms/Button'
-import SettingTokenCreate from '../../../../shared/components/organisms/Settings/atoms/SettingTokenCreate'
+import SettingTokenCreate from '../../../../shared/components/organisms/Settings/molecules/SettingTokenCreate'
import Flexbox from '../../../../shared/components/atoms/Flexbox'
const ApiTab = () => {
From 31a6743fc4d1369cea6b6e7549b01816426fd039 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 15:26:54 +0900
Subject: [PATCH 56/91] Fix Alignment
---
src/shared/components/atoms/Button.tsx | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/shared/components/atoms/Button.tsx b/src/shared/components/atoms/Button.tsx
index 2d497a758c..afa2106c93 100644
--- a/src/shared/components/atoms/Button.tsx
+++ b/src/shared/components/atoms/Button.tsx
@@ -164,6 +164,11 @@ const StyledButton = styled.button`
margin-left: 5px;
}
+ .button__label {
+ display: flex;
+ align-items: center;
+ }
+
.button__icon {
flex: 0 0 auto;
}
From 1ab0b26f0851d3e5792e6cb8cbda8b54d2af601f Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 15:27:10 +0900
Subject: [PATCH 57/91] Changed Import
---
src/cloud/components/organisms/settings/SettingsComponent.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index 54ef420f28..1780d153b7 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -25,7 +25,7 @@ import PreferencesTab from './PreferencesTab'
import ApiTab from './ApiTab'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import Settings from '../../../../shared/components/organisms/Settings'
-import SettingSidenavHeader from '../../../../shared/components/organisms/Settings/atoms/SettingSidenavHeader'
+import SettingSidenavHeader from '../../../../shared/components/organisms/Settings/molecules/SettingSidenavHeader'
import SettingSidenav from '../../../../shared/components/organisms/Settings/atoms/SettingSidenav'
import SettingMain from '../../../../shared/components/organisms/Settings/atoms/SettingMain'
import SettingTabButton from '../../../../shared/components/organisms/Settings/atoms/SettingTabButton'
From bd347c620e0de5559eb30b772add84a219eb61a5 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Mon, 10 May 2021 15:27:31 +0900
Subject: [PATCH 58/91] Changed Sizes fo Input & Select
---
.../components/organisms/Settings/atoms/SettingInput.tsx | 4 +++-
.../components/organisms/Settings/atoms/SettingSelect.tsx | 3 ++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/shared/components/organisms/Settings/atoms/SettingInput.tsx b/src/shared/components/organisms/Settings/atoms/SettingInput.tsx
index 1bcd2decf0..010ff48254 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingInput.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingInput.tsx
@@ -5,6 +5,7 @@ interface SettingInputProps {
label?: string
value?: string
placeholder?: string
+ type?: string
onChange?: React.ChangeEventHandler
}
@@ -28,7 +29,8 @@ const Container = styled.div`
flex-shrink: 1;
width: 100%;
height: 40px;
- max-width: 400px;
+ min-width: 300px;
+ max-width: 450px;
padding: ${({ theme }) => theme.sizes.spaces.xsm}px
${({ theme }) => theme.sizes.spaces.sm}px;
background-color: ${({ theme }) => theme.colors.background.primary};
diff --git a/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx b/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
index 7123519e7c..e95ab4d91e 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
@@ -36,7 +36,8 @@ const Container = styled.div`
select {
width: 100%;
height: 40px;
- max-width: 400px;
+ min-width: 300px;
+ max-width: 450px;
padding: 0 ${({ theme }) => theme.sizes.spaces.sm}px;
border-radius: 4px;
background-color: ${({ theme }) => theme.colors.background.primary};
From a021c7eac1cd1df250e3430a834f9ea796ffd5d2 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 15 May 2021 12:33:00 +0900
Subject: [PATCH 59/91] Put Close Button Back
---
.../organisms/settings/SettingsComponent.tsx | 16 +++++++--
.../Settings/atoms/SettingCloseButton.tsx | 33 +++++++++++++++++++
.../components/organisms/Settings/index.tsx | 2 +-
3 files changed, 48 insertions(+), 3 deletions(-)
create mode 100644 src/shared/components/organisms/Settings/atoms/SettingCloseButton.tsx
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index 1780d153b7..07b2a5c612 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -7,7 +7,7 @@ import {
isSingleKeyEventOutsideOfInput,
} from '../../../lib/keyboard'
import { useTranslation } from 'react-i18next'
-import { mdiDomain, mdiAccountCircleOutline } from '@mdi/js'
+import { mdiDomain, mdiAccountCircleOutline, mdiClose } from '@mdi/js'
import PersonalInfoTab from './PersonalInfoTab'
import { usePage } from '../../../lib/stores/pageStore'
import TeamInfoTab from './TeamInfoTab'
@@ -29,6 +29,8 @@ import SettingSidenavHeader from '../../../../shared/components/organisms/Settin
import SettingSidenav from '../../../../shared/components/organisms/Settings/atoms/SettingSidenav'
import SettingMain from '../../../../shared/components/organisms/Settings/atoms/SettingMain'
import SettingTabButton from '../../../../shared/components/organisms/Settings/atoms/SettingTabButton'
+import Icon from '../../../../shared/components/atoms/Icon'
+import SettingCloseButton from '../../../../shared/components/organisms/Settings/atoms/SettingCloseButton'
const SettingsComponent = () => {
const { t } = useTranslation()
@@ -196,7 +198,17 @@ const SettingsComponent = () => {
)}
}
- content={{content} }
+ content={
+
+ {content}
+
+
+
+
+ }
>
)
}
diff --git a/src/shared/components/organisms/Settings/atoms/SettingCloseButton.tsx b/src/shared/components/organisms/Settings/atoms/SettingCloseButton.tsx
new file mode 100644
index 0000000000..3926a47bd0
--- /dev/null
+++ b/src/shared/components/organisms/Settings/atoms/SettingCloseButton.tsx
@@ -0,0 +1,33 @@
+import styled from '../../../../lib/styled'
+
+const SettingCloseButton = styled.div`
+ position: absolute;
+ top: ${({ theme }) => theme.sizes.spaces.md}px;
+ right: ${({ theme }) => theme.sizes.spaces.md}px;
+ width: 26px;
+ height: 26px;
+ background-color: transparent;
+ border: none;
+ cursor: pointer;
+ color: ${({ theme }) => theme.colors.icon.default};
+ transition: 200ms color;
+
+ &:hover,
+ &:focus {
+ color: ${({ theme }) => theme.colors.icon.hover} !important;
+ }
+
+ &:active {
+ color: ${({ theme }) => theme.colors.icon.active} !important;
+ }
+
+ &:disabled {
+ &:hover,
+ &:focus,
+ &:active {
+ cursor: not-allowed;
+ }
+ }
+`
+
+export default SettingCloseButton
diff --git a/src/shared/components/organisms/Settings/index.tsx b/src/shared/components/organisms/Settings/index.tsx
index bc6125bc76..a5e84fc7d3 100644
--- a/src/shared/components/organisms/Settings/index.tsx
+++ b/src/shared/components/organisms/Settings/index.tsx
@@ -24,7 +24,7 @@ const Container = styled.div`
align-items: center;
justify-content: center;
position: fixed;
- left: 40px;
+ left: 0;
top: 0;
right: 0;
bottom: 0;
From f777e51c27334e2fd54f1be068f96d34d2532e91 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 15 May 2021 14:47:27 +0900
Subject: [PATCH 60/91] Adjusted Pricing Table Styles
---
.../organisms/Subscription/PlanTables.tsx | 65 ++++++++++---------
.../organisms/settings/UpgradeTab.tsx | 44 ++++++-------
2 files changed, 55 insertions(+), 54 deletions(-)
diff --git a/src/cloud/components/organisms/Subscription/PlanTables.tsx b/src/cloud/components/organisms/Subscription/PlanTables.tsx
index efa5e9741b..300bd46fac 100644
--- a/src/cloud/components/organisms/Subscription/PlanTables.tsx
+++ b/src/cloud/components/organisms/Subscription/PlanTables.tsx
@@ -12,8 +12,8 @@ import {
revisionHistoryStandardDays,
standardPlanStorageMb,
} from '../../../lib/subscription'
-import CustomButton from '../../atoms/buttons/CustomButton'
import cc from 'classcat'
+import Button from '../../../../shared/components/atoms/Button'
interface PlanTablesProps {
team: SerializedTeam
@@ -67,7 +67,7 @@ const PlanTables = ({
onTrialCallback()
}}
>
- Try it for free
+ 7 days free trial
)
@@ -83,20 +83,25 @@ const PlanTables = ({
Free
$0
+
+ per user
+
+ per month
+
{selectedPlan === 'free' ? (
-
Current Plan
-
+
) : (
-
+
Downgrade
-
+
)}
@@ -104,23 +109,24 @@ const PlanTables = ({
Standard
$3
-
per member per month
+
+ per user
+
+ per month
+
{selectedPlan === 'standard' ? (
-
Current Plan
-
+
) : (
-
+
{selectedPlan === 'free' ? 'Upgrade' : 'Downgrade'}
-
+
)}
@@ -128,21 +134,25 @@ const PlanTables = ({
Pro
$8
-
per member per month
+
+ per user
+
+ per month
+
{selectedPlan === 'pro' ? (
-
Current Plan
-
+
) : (
-
+
Upgrade
-
+
)}
{freeTrialContent}
@@ -351,12 +361,6 @@ const Container = styled.div`
.upgrade-btn {
width: 100%;
margin: ${({ theme }) => theme.fontSizes.xsmall}px 0;
- padding: 0px ${({ theme }) => theme.space.xxsmall}px !important;
- display: flex;
- align-items: center;
- justify-content: center;
- height: 40px;
- line-height: inherit;
}
tr td {
@@ -366,9 +370,8 @@ const Container = styled.div`
text-align: left;
min-height: 30px;
- &:not(.first) {
- padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.small}px;
+ &:not(.first):not(.header) {
+ padding: ${({ theme }) => theme.space.xsmall}px;
}
&.first {
diff --git a/src/cloud/components/organisms/settings/UpgradeTab.tsx b/src/cloud/components/organisms/settings/UpgradeTab.tsx
index ef38f5faab..80f07ecf71 100644
--- a/src/cloud/components/organisms/settings/UpgradeTab.tsx
+++ b/src/cloud/components/organisms/settings/UpgradeTab.tsx
@@ -87,29 +87,27 @@ const UpgradeTab = () => {
/>
)}
-
- onUpgradeCallback('standard')}
- onProCallback={() => onUpgradeCallback('pro')}
- onTrialCallback={() => setShowTrialPopup(true)}
- />
-
- * For larger businesses or those in highly regulated
- industries, please{' '}
-
- contact our sales department
-
- .
-
-
+ onUpgradeCallback('standard')}
+ onProCallback={() => onUpgradeCallback('pro')}
+ onTrialCallback={() => setShowTrialPopup(true)}
+ />
+
+ * For larger businesses or those in highly regulated industries,
+ please{' '}
+
+ contact our sales department
+
+ .
+
>
}
From b36270537266ff97ca210b4d941c87fe88501703 Mon Sep 17 00:00:00 2001
From: Elle Kasai
Date: Sat, 15 May 2021 15:03:07 +0900
Subject: [PATCH 61/91] Replaced to SettingLink
---
.../organisms/Subscription/PlanTables.tsx | 15 +++------------
.../organisms/settings/UpgradeTab.tsx | 6 +++---
.../organisms/Settings/atoms/SettingLink.tsx | 17 +++++++----------
3 files changed, 13 insertions(+), 25 deletions(-)
diff --git a/src/cloud/components/organisms/Subscription/PlanTables.tsx b/src/cloud/components/organisms/Subscription/PlanTables.tsx
index 300bd46fac..a8a1d9c365 100644
--- a/src/cloud/components/organisms/Subscription/PlanTables.tsx
+++ b/src/cloud/components/organisms/Subscription/PlanTables.tsx
@@ -14,6 +14,7 @@ import {
} from '../../../lib/subscription'
import cc from 'classcat'
import Button from '../../../../shared/components/atoms/Button'
+import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
interface PlanTablesProps {
team: SerializedTeam
@@ -60,7 +61,7 @@ const PlanTables = ({
return (
- {
e.preventDefault()
@@ -68,7 +69,7 @@ const PlanTables = ({
}}
>
7 days free trial
-
+
)
}, [subscription, team, onTrialCallback])
@@ -299,16 +300,6 @@ const PlanTables = ({
)
}
-const StyledTrialLink = styled.a`
- text-decoration: underline;
- font-size: ${({ theme }) => theme.fontSizes.default}px;
- transition: 200ms color;
- color: ${({ theme }) => theme.primaryTextColor};
- &:hover {
- text-decoration: none;
- }
-`
-
const Container = styled.div`
width: 100%;
overflow: auto;
diff --git a/src/cloud/components/organisms/settings/UpgradeTab.tsx b/src/cloud/components/organisms/settings/UpgradeTab.tsx
index 80f07ecf71..cd25ec1bcd 100644
--- a/src/cloud/components/organisms/settings/UpgradeTab.tsx
+++ b/src/cloud/components/organisms/settings/UpgradeTab.tsx
@@ -11,11 +11,11 @@ import { useGlobalData } from '../../../lib/stores/globalData'
import ColoredBlock from '../../atoms/ColoredBlock'
import FreeTrialPopup from '../FreeTrialPopup'
import { stripePublishableKey } from '../../../lib/consts'
-import CustomLink from '../../atoms/Link/CustomLink'
import PlanTables from '../Subscription/PlanTables'
import { UpgradePlans } from '../../../lib/stripe'
import styled from '../../../lib/styled'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
+import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
const stripePromise = loadStripe(stripePublishableKey)
@@ -98,14 +98,14 @@ const UpgradeTab = () => {
* For larger businesses or those in highly regulated industries,
please{' '}
-
contact our sales department
-
+
.
diff --git a/src/shared/components/organisms/Settings/atoms/SettingLink.tsx b/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
index f7533cc382..9d1d6ca145 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
@@ -1,16 +1,13 @@
import styled from '../../../../lib/styled'
-import Link from '../../../atoms/Link'
-const SettingLink = styled(Link)`
- a {
- color: ${({ theme }) => theme.colors.text.link};
- text-decoration: none;
+const SettingLink = styled.a`
+ color: ${({ theme }) => theme.colors.text.link};
+ text-decoration: none;
- &:hover,
- &:focus {
- color: ${({ theme }) => theme.colors.text.link};
- text-decoration: underline;
- }
+ &:hover,
+ &:focus {
+ color: ${({ theme }) => theme.colors.text.link};
+ text-decoration: underline;
}
`
From 2d955e7dbd56d0403ef112d86f8c48c8a920a75f Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 07:27:06 +0900
Subject: [PATCH 62/91] remove setting link
---
src/cloud/components/Application.tsx | 2 +
.../components/atoms/Link/AccountLink.tsx | 8 +-
.../atoms/Link/{Link.tsx => CloudLink.tsx} | 22 +-
src/cloud/components/atoms/Link/TeamLink.tsx | 9 +-
.../Modal/contents/Doc/GuestsModal/index.tsx | 10 +-
.../organisms/RightSideTopBar/BreadCrumbs.tsx | 404 ------------------
.../SideNavigator/SideNavigatorItem.tsx | 6 +-
.../Sidebar/SidebarTeamPickerContext.tsx | 6 +-
.../organisms/Subscription/PlanTables.tsx | 6 +-
.../components/organisms/settings/ApiTab.tsx | 9 +-
.../organisms/settings/MembersTab.tsx | 10 +-
.../organisms/settings/UpgradeTab.tsx | 11 +-
src/shared/components/atoms/Link.tsx | 3 +
.../organisms/Settings/atoms/SettingLink.tsx | 14 -
14 files changed, 39 insertions(+), 481 deletions(-)
rename src/cloud/components/atoms/Link/{Link.tsx => CloudLink.tsx} (77%)
delete mode 100644 src/cloud/components/organisms/RightSideTopBar/BreadCrumbs.tsx
delete mode 100644 src/shared/components/organisms/Settings/atoms/SettingLink.tsx
diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx
index 1244c4c27b..a72680d6dd 100644
--- a/src/cloud/components/Application.tsx
+++ b/src/cloud/components/Application.tsx
@@ -219,6 +219,8 @@ const Application = ({
if (query.settings === 'upgrade') {
openSettingsTab('teamUpgrade')
}
+
+ openSettingsTab('personalInfo')
})
useEffect(() => {
diff --git a/src/cloud/components/atoms/Link/AccountLink.tsx b/src/cloud/components/atoms/Link/AccountLink.tsx
index 94212d4282..1897590d2a 100644
--- a/src/cloud/components/atoms/Link/AccountLink.tsx
+++ b/src/cloud/components/atoms/Link/AccountLink.tsx
@@ -1,6 +1,6 @@
import React, { FC } from 'react'
import querystring from 'querystring'
-import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
+import CloudLink from './CloudLink'
export type AccountLinkIntent = 'delete'
@@ -16,22 +16,20 @@ interface AccountLinkProps {
const AccountLink: FC = ({
intent = 'delete',
className,
- style,
children,
query,
draggable = false,
beforeNavigate,
}) => {
return (
-
{children}
-
+
)
}
diff --git a/src/cloud/components/atoms/Link/Link.tsx b/src/cloud/components/atoms/Link/CloudLink.tsx
similarity index 77%
rename from src/cloud/components/atoms/Link/Link.tsx
rename to src/cloud/components/atoms/Link/CloudLink.tsx
index d0a377b8b4..0e3f9f2274 100644
--- a/src/cloud/components/atoms/Link/Link.tsx
+++ b/src/cloud/components/atoms/Link/CloudLink.tsx
@@ -1,31 +1,24 @@
-import React, {
- FC,
- useCallback,
- MouseEventHandler,
- CSSProperties,
- FocusEvent,
-} from 'react'
+import React, { FC, useCallback, MouseEventHandler, FocusEvent } from 'react'
import { useRouter, Url } from '../../../lib/router'
import { stringifyUrl } from '../../../lib/utils/string'
+import Link from '../../../../shared/components/atoms/Link'
-export interface LinkProps {
+export interface CloudLinkProps {
href: Url
id?: string
className?: string
tabIndex?: number
draggable?: boolean
- style?: CSSProperties
beforeNavigate?: () => void | Promise
onFocus?: (event: FocusEvent) => void
}
-const Link: FC = ({
+const CloudLink: FC = ({
href,
id,
className,
tabIndex,
draggable,
- style,
beforeNavigate,
onFocus,
children,
@@ -44,7 +37,7 @@ const Link: FC = ({
)
return (
- = ({
className={className}
tabIndex={tabIndex}
draggable={draggable}
- style={style}
>
{children}
-
+
)
}
-export default Link
+export default CloudLink
diff --git a/src/cloud/components/atoms/Link/TeamLink.tsx b/src/cloud/components/atoms/Link/TeamLink.tsx
index 1d326b0596..d92cac4944 100644
--- a/src/cloud/components/atoms/Link/TeamLink.tsx
+++ b/src/cloud/components/atoms/Link/TeamLink.tsx
@@ -2,7 +2,7 @@ import React, { useCallback } from 'react'
import querystring from 'querystring'
import { SerializedTeam } from '../../../interfaces/db/team'
import { useRouter } from '../../../lib/router'
-import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
+import CloudLink from './CloudLink'
export type TeamLinkIntent =
| 'index'
@@ -25,7 +25,6 @@ interface TeamLinkProps {
team: TeamIdProps
intent?: TeamLinkIntent
className?: string
- style?: React.CSSProperties
children?: React.ReactNode
query?: any
beforeNavigate?: () => void
@@ -38,7 +37,6 @@ const TeamLink = ({
intent = 'index',
team,
className,
- style,
children,
query,
beforeNavigate,
@@ -47,17 +45,16 @@ const TeamLink = ({
tabIndex = 0,
}: TeamLinkProps) => {
return (
-
{children}
-
+
)
}
diff --git a/src/cloud/components/organisms/Modal/contents/Doc/GuestsModal/index.tsx b/src/cloud/components/organisms/Modal/contents/Doc/GuestsModal/index.tsx
index 6d9c8fb4c8..cbf5409035 100644
--- a/src/cloud/components/organisms/Modal/contents/Doc/GuestsModal/index.tsx
+++ b/src/cloud/components/organisms/Modal/contents/Doc/GuestsModal/index.tsx
@@ -10,7 +10,7 @@ import { guestsPerMember } from '../../../../../../lib/subscription'
import plur from 'plur'
import GuestInvitesSection from '../../../../../molecules/GuestInvitesSection'
import { useModal } from '../../../../../../../shared/lib/stores/modal'
-import SettingLink from '../../../../../../../shared/components/organisms/Settings/atoms/SettingLink'
+import { ExternalLink } from '../../../../../../../shared/components/atoms/Link'
interface GuestsModalProps {
docId: string
@@ -64,13 +64,9 @@ const GuestsModal = ({ docId, teamId }: GuestsModalProps) => {
permissions.length * guestsPerMember - guestsMap.size
} remaining ${plur('seat', permissions.length)}. `
: 'No Remaining seats. '}
-
+
See how it works
-
+
diff --git a/src/cloud/components/organisms/RightSideTopBar/BreadCrumbs.tsx b/src/cloud/components/organisms/RightSideTopBar/BreadCrumbs.tsx
deleted file mode 100644
index 604cfa7244..0000000000
--- a/src/cloud/components/organisms/RightSideTopBar/BreadCrumbs.tsx
+++ /dev/null
@@ -1,404 +0,0 @@
-import React, {
- useMemo,
- useState,
- useRef,
- useCallback,
- useEffect,
- FocusEventHandler,
- MouseEventHandler,
-} from 'react'
-import { useNav } from '../../../lib/stores/nav'
-import { SerializedTeam } from '../../../interfaces/db/team'
-import { SerializedFolderWithBookmark } from '../../../interfaces/db/folder'
-import FolderLink from '../../atoms/Link/FolderLink'
-import WorkspaceLink from '../../atoms/Link/WorkspaceLink'
-import styled from '../../../lib/styled'
-import TeamLink from '../../atoms/Link/TeamLink'
-import ToolbarSlashSeparator from './TopBarSlashSeparator'
-import Icon from '../../atoms/Icon'
-import {
- mdiFolderAccountOutline,
- mdiDotsHorizontal,
- mdiFolderOutline,
- mdiSubdirectoryArrowRight,
-} from '@mdi/js'
-import { isChildNode } from '../../../lib/dom'
-import Flexbox from '../../atoms/Flexbox'
-import { useContextMenuKeydownHandler } from '../../../lib/keyboard'
-import { useMediaQuery } from 'react-responsive'
-import { usePage } from '../../../lib/stores/pageStore'
-
-interface BreadCrumbsProps {
- team: SerializedTeam
- minimize?: boolean
- path?: string
- addedNodes?: React.ReactNode
-}
-
-type BreadCrumbs = {
- folderLabel: string
- folderPathname: string
-}[]
-
-const BreadCrumbs = ({ team, path, addedNodes }: BreadCrumbsProps) => {
- const {
- currentPath: defaultPath,
- currentWorkspaceId,
- workspacesMap,
- foldersMap,
- } = useNav()
- const [
- showingParentFolderListPopup,
- setShowingParentFolderListPopup,
- ] = useState(false)
- const parentFolderListPopupRef = useRef(null)
- const [contextOffset, setContextOffset] = useState(0)
- const { currentUserPermissions } = usePage()
-
- useEffect(() => {
- if (parentFolderListPopupRef.current != null) {
- parentFolderListPopupRef.current.focus()
- }
- }, [showingParentFolderListPopup])
-
- const showParentFolderListPopup: MouseEventHandler = useCallback(
- (event) => {
- setContextOffset(event.currentTarget.offsetLeft)
- setShowingParentFolderListPopup(true)
- },
- []
- )
-
- const hideParentFolderListPopup: FocusEventHandler = useCallback(
- (event) => {
- if (
- parentFolderListPopupRef.current != null &&
- !isChildNode(
- parentFolderListPopupRef.current,
- event.relatedTarget as HTMLElement | null
- )
- ) {
- setShowingParentFolderListPopup(false)
- }
- },
- []
- )
-
- const currentWorkspace = useMemo(() => {
- if (currentWorkspaceId == null) {
- return undefined
- }
- return workspacesMap.get(currentWorkspaceId)
- }, [currentWorkspaceId, workspacesMap])
-
- const foldersMapByPathnames = useMemo(() => {
- const folderMap = new Map()
- const folders = [...foldersMap.values()]
- folders.forEach((folder) => {
- if (folder.teamId === team.id) folderMap.set(folder.pathname, folder)
- })
- return folderMap
- }, [foldersMap, team])
-
- const breadCrumbs = useMemo(() => {
- const currentPath = path != null ? path : defaultPath
- if (currentPath === '/') {
- return []
- }
-
- const folders = currentPath.substring(1).split('/')
- const thread = folders.map((folderName, index) => {
- const folderPathname = `/${folders.slice(0, index + 1).join('/')}`
- return {
- folderLabel: folderName,
- folderPathname,
- }
- })
- return thread as BreadCrumbs
- }, [defaultPath, path])
-
- const parentBreadCrumbs = new Set(
- breadCrumbs
- .slice(0, breadCrumbs.length - 1)
- .map((breadcrumb) => breadcrumb.folderPathname)
- )
- const directParentBreadCrumb = breadCrumbs[breadCrumbs.length - 1]
- const directParentFolder =
- directParentBreadCrumb != null
- ? foldersMapByPathnames.get(directParentBreadCrumb.folderPathname)
- : null
-
- useContextMenuKeydownHandler(parentFolderListPopupRef)
-
- const isTabletOrMobile = useMediaQuery({ maxWidth: 1080 })
-
- if (currentUserPermissions == null) {
- return (
-
-
- Shared
- {addedNodes != null && }
-
- {addedNodes}
-
- )
- }
-
- return (
-
- {showingParentFolderListPopup && (
-
-
- {isTabletOrMobile && currentWorkspace != null && (
-
- {currentWorkspace.default ? (
-
-
- {currentWorkspace.name}
-
- ) : (
-
-
- {currentWorkspace.name}
-
- )}
-
- )}
-
- {breadCrumbs.map((elem, index) => {
- const folder = foldersMapByPathnames.get(elem.folderPathname)
- if (
- !isTabletOrMobile &&
- !parentBreadCrumbs.has(elem.folderPathname)
- ) {
- return null
- }
-
- return (
-
- {folder != null ? (
-
- {(index !== 0 || (index === 0 && isTabletOrMobile)) && (
-
- )}
-
- {folder.name}
-
- ) : (
- {elem.folderLabel}
- )}
-
- )
- })}
-
-
- )}
-
- {isTabletOrMobile ? (
-
-
-
-
- {addedNodes != null && }
-
- ) : (
-
- {currentWorkspace != null && (
- <>
- {currentWorkspace.default ? (
-
-
- {currentWorkspace.name}
-
- ) : (
-
-
- {currentWorkspace.name}
-
- )}
- >
- )}
- {breadCrumbs.length > 1 && (
- <>
-
-
-
-
- >
- )}
-
- {directParentBreadCrumb != null && (
- <>
- {directParentFolder != null ? (
-
-
- {directParentFolder.name}
-
- ) : (
- {directParentBreadCrumb.folderLabel}
- )}
-
- {addedNodes != null && }
- >
- )}
-
- )}
- {addedNodes}
-
- )
-}
-
-const StyledBreadCrumbs = styled.div`
- display: flex;
- flex: 1;
- min-width: 0;
- height: 100%;
- align-items: center;
- color: ${({ theme }) => theme.subtleTextColor};
- overflow-x: hidden;
-
- .padded {
- padding-left: ${({ theme }) => theme.space.small}px;
- }
-
- .bread-crumb-link {
- display: flex;
- align-items: center;
- padding: 2px 4px;
- border-radius: 3px;
- white-space: nowrap;
- background-color: transparent;
- color: ${({ theme }) => theme.baseTextColor};
- cursor: pointer;
- text-decoration: none !important;
-
- .label {
- margin-left: 4px;
- }
- .hoverIcon {
- margin-left: 4px;
- opacity: 0;
- }
-
- &:hover,
- &:focus {
- background-color: ${({ theme }) => theme.subtleBackgroundColor};
- .hoverIcon {
- opacity: 1;
- }
- }
- }
-`
-
-const ParentFolderListPopup = styled.div`
- position: absolute;
- z-index: 1000;
- max-height: 300px;
- top: 100%;
- background-color: ${({ theme }) => theme.baseBackgroundColor};
- border: 1px solid ${({ theme }) => theme.baseBorderColor};
- border-radius: 4px;
- overflow-y: auto;
- overflow-x: hidden;
- & > ul {
- padding: 0;
- margin: 0;
- list-style: none;
- }
-
- .parentFolderItem {
- padding-right: 5px;
- background-color: transparent;
- color: ${({ theme }) => theme.subtleTextColor};
- cursor: pointer;
- text-decoration: none !important;
- &:hover,
- &:focus {
- color: ${({ theme }) => theme.emphasizedTextColor};
- & > .hoverIcon {
- opacity: 1;
- }
- }
-
- display: flex;
- align-items: center;
- & > .icon {
- margin-right: 4px;
- }
- & > .hoverIcon {
- margin-left: 4px;
- opacity: 0;
- }
- }
-`
-
-export default BreadCrumbs
diff --git a/src/cloud/components/organisms/Sidebar/SideNavigator/SideNavigatorItem.tsx b/src/cloud/components/organisms/Sidebar/SideNavigator/SideNavigatorItem.tsx
index 5a7be09c43..0149e72f92 100644
--- a/src/cloud/components/organisms/Sidebar/SideNavigator/SideNavigatorItem.tsx
+++ b/src/cloud/components/organisms/Sidebar/SideNavigator/SideNavigatorItem.tsx
@@ -9,7 +9,7 @@ import {
} from './styled'
import styled from '../../../../lib/styled'
import IconMdi from '../../../atoms/IconMdi'
-import Link from '../../../atoms/Link/Link'
+import CloudLink from '../../../atoms/Link/CloudLink'
import { Url } from '../../../../lib/router'
type SideNavNextLink = {
@@ -64,7 +64,7 @@ const SideNavigatorItem = ({
const labelContent = useMemo(() => {
if (href != null) {
return (
- setFocused(true)}
id={`tree-${elementId}`}
@@ -72,7 +72,7 @@ const SideNavigatorItem = ({
href={href}
>
{label}
-
+
)
}
diff --git a/src/cloud/components/organisms/Sidebar/SidebarTeamPickerContext.tsx b/src/cloud/components/organisms/Sidebar/SidebarTeamPickerContext.tsx
index da9fb266f8..ee1a48b7c0 100644
--- a/src/cloud/components/organisms/Sidebar/SidebarTeamPickerContext.tsx
+++ b/src/cloud/components/organisms/Sidebar/SidebarTeamPickerContext.tsx
@@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next'
import TeamLink from '../../atoms/Link/TeamLink'
import cc from 'classcat'
import { usePage } from '../../../lib/stores/pageStore'
-import Link from '../../atoms/Link/Link'
+import CloudLink from '../../atoms/Link/CloudLink'
import { getHexFromUUID } from '../../../lib/utils/string'
import { stringify } from 'querystring'
import IconMdi from '../../atoms/IconMdi'
@@ -95,7 +95,7 @@ const SidebarTeamPickerContext = ({
{invites.map((invite) => {
const query = { t: invite.team.id, i: getHexFromUUID(invite.id) }
return (
- - invited
-
+
)
})}
diff --git a/src/cloud/components/organisms/Subscription/PlanTables.tsx b/src/cloud/components/organisms/Subscription/PlanTables.tsx
index a8a1d9c365..56bbb80b6b 100644
--- a/src/cloud/components/organisms/Subscription/PlanTables.tsx
+++ b/src/cloud/components/organisms/Subscription/PlanTables.tsx
@@ -14,7 +14,7 @@ import {
} from '../../../lib/subscription'
import cc from 'classcat'
import Button from '../../../../shared/components/atoms/Button'
-import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
+import Link from '../../../../shared/components/atoms/Link'
interface PlanTablesProps {
team: SerializedTeam
@@ -61,7 +61,7 @@ const PlanTables = ({
return (
- {
e.preventDefault()
@@ -69,7 +69,7 @@ const PlanTables = ({
}}
>
7 days free trial
-
+
)
}, [subscription, team, onTrialCallback])
diff --git a/src/cloud/components/organisms/settings/ApiTab.tsx b/src/cloud/components/organisms/settings/ApiTab.tsx
index a382d01b72..08b36da073 100644
--- a/src/cloud/components/organisms/settings/ApiTab.tsx
+++ b/src/cloud/components/organisms/settings/ApiTab.tsx
@@ -7,10 +7,10 @@ import { usePage } from '../../../lib/stores/pageStore'
import Icon from '../../atoms/IconMdi'
import { mdiOpenInNew } from '@mdi/js'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
-import SettingLink from '../../../../shared/components/organisms/Settings/atoms/SettingLink'
import Button from '../../../../shared/components/atoms/Button'
import SettingTokenCreate from '../../../../shared/components/organisms/Settings/molecules/SettingTokenCreate'
import Flexbox from '../../../../shared/components/atoms/Flexbox'
+import { ExternalLink } from '../../../../shared/components/atoms/Link'
const ApiTab = () => {
const { team } = usePage()
@@ -51,13 +51,10 @@ const ApiTab = () => {
Access Tokens
See the{' '}
-
+
documentation for Boost Note for Teams API{' '}
-
+
{
const { t } = useTranslation()
@@ -604,13 +604,9 @@ const MembersTab = () => {
They can be invited to individual documents but not an
entire workspace.
{` `}
-
+
See how it works
-
+
{
* For larger businesses or those in highly regulated industries,
please{' '}
-
+
contact our sales department
-
+
.
diff --git a/src/shared/components/atoms/Link.tsx b/src/shared/components/atoms/Link.tsx
index 8512c34299..e89e015413 100644
--- a/src/shared/components/atoms/Link.tsx
+++ b/src/shared/components/atoms/Link.tsx
@@ -10,6 +10,7 @@ interface HyperLinkProps {
id?: string
href: string
className?: string
+ tabIndex?: number
onContextMenu?: MouseEventHandler
onFocus?: FocusEventHandler
draggable?: boolean
@@ -57,10 +58,12 @@ const Container = styled.a`
cursor: pointer;
&:hover {
+ color: ${({ theme }) => theme.colors.text.link};
text-decoration: underline;
}
&:focus {
+ color: ${({ theme }) => theme.colors.text.link};
opacity: 0.8;
}
`
diff --git a/src/shared/components/organisms/Settings/atoms/SettingLink.tsx b/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
deleted file mode 100644
index 9d1d6ca145..0000000000
--- a/src/shared/components/organisms/Settings/atoms/SettingLink.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import styled from '../../../../lib/styled'
-
-const SettingLink = styled.a`
- color: ${({ theme }) => theme.colors.text.link};
- text-decoration: none;
-
- &:hover,
- &:focus {
- color: ${({ theme }) => theme.colors.text.link};
- text-decoration: underline;
- }
-`
-
-export default SettingLink
From 1f6281d26251f7931c920ccbf6d697d568f98e7e Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 08:04:13 +0900
Subject: [PATCH 63/91] fix team invites section
---
.../molecules/TeamInvitesSection.tsx | 79 +++++++++++--------
.../molecules/Form/atoms/FormRow.tsx | 0
.../molecules/Form/atoms/FormSelect.tsx | 8 +-
.../components/molecules/Form/index.tsx | 28 +++++--
4 files changed, 75 insertions(+), 40 deletions(-)
create mode 100644 src/shared/components/molecules/Form/atoms/FormRow.tsx
diff --git a/src/cloud/components/molecules/TeamInvitesSection.tsx b/src/cloud/components/molecules/TeamInvitesSection.tsx
index 4fea03f301..640e227ffd 100644
--- a/src/cloud/components/molecules/TeamInvitesSection.tsx
+++ b/src/cloud/components/molecules/TeamInvitesSection.tsx
@@ -1,6 +1,5 @@
import React, { useState, useCallback } from 'react'
import {
- SectionRow,
SectionList,
SectionListItem,
SectionInLineIcon,
@@ -19,12 +18,10 @@ import IconMdi from '../atoms/IconMdi'
import { mdiClose } from '@mdi/js'
import { Spinner } from '../atoms/Spinner'
import ErrorBlock from '../atoms/ErrorBlock'
-import CustomButton from '../atoms/buttons/CustomButton'
-import { SelectChangeEventHandler } from '../../lib/utils/events'
import { SerializedUserTeamPermissions } from '../../interfaces/db/userTeamPermissions'
import Flexbox from '../atoms/Flexbox'
-import SettingSelect from '../../../shared/components/organisms/Settings/atoms/SettingSelect'
-import SettingInput from '../../../shared/components/organisms/Settings/atoms/SettingInput'
+import Form from '../../../shared/components/molecules/Form'
+import { FormSelectOption } from '../../../shared/components/molecules/Form/atoms/FormSelect'
interface TeamInvitesSectionProps {
userPermissions: SerializedUserTeamPermissions
@@ -130,13 +127,13 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
[messageBox, team]
)
- const selectRole: SelectChangeEventHandler = useCallback(
- (event) => {
+ const selectRole = useCallback(
+ (option: FormSelectOption) => {
if (userPermissions.role !== 'admin') {
return
}
- setRole(event.target.value as TeamPermissionType)
+ setRole(option.value as TeamPermissionType)
},
[setRole, userPermissions]
)
@@ -147,30 +144,48 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
Invite with Email
{sending && }
-
+
{role === 'admin' ? (
Admins can handle billing, remove or promote/demote members.
diff --git a/src/shared/components/molecules/Form/atoms/FormRow.tsx b/src/shared/components/molecules/Form/atoms/FormRow.tsx
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/shared/components/molecules/Form/atoms/FormSelect.tsx b/src/shared/components/molecules/Form/atoms/FormSelect.tsx
index c23c62d7ab..9fbbbc4fed 100644
--- a/src/shared/components/molecules/Form/atoms/FormSelect.tsx
+++ b/src/shared/components/molecules/Form/atoms/FormSelect.tsx
@@ -74,9 +74,15 @@ const Container = styled.div`
width: 0;
}
+ .form__select .form__select__control,
+ .form__select .form__select__indicator,
+ .form__select .form__select__indicators {
+ height: 32px;
+ min-height: 32px;
+ }
+
.form__select .form__select__control {
width: 100%;
- height: 40px;
color: ${({ theme }) => theme.colors.text.subtle};
border: none;
&.form__select__control--is-focused {
diff --git a/src/shared/components/molecules/Form/index.tsx b/src/shared/components/molecules/Form/index.tsx
index 100a7a0eaf..c472c3b472 100644
--- a/src/shared/components/molecules/Form/index.tsx
+++ b/src/shared/components/molecules/Form/index.tsx
@@ -2,20 +2,24 @@ import React, { useState } from 'react'
import styled from '../../../lib/styled'
import { LoadingButton, ButtonProps } from '../../atoms/Button'
import FormInput, { FormInputProps } from './atoms/FormInput'
-import { FormSelectProps } from './atoms/FormSelect'
+import FormSelect, { FormSelectProps } from './atoms/FormSelect'
import cc from 'classcat'
import { AppComponent } from '../../../lib/types'
-import { FormSelect } from '../../../../components/atoms/form'
import FormEmoji, { FormEmojiProps } from './atoms/FormEmoji'
interface FormProps {
rows: FormRowProps[]
onSubmit: React.FormEventHandler
- submitButton?: ButtonProps & { label: React.ReactNode; spinning?: boolean }
+ submitButton?: LabelButtonProps
onCancel?: () => void
}
+type LabelButtonProps = ButtonProps & {
+ label: React.ReactNode
+ spinning?: boolean
+}
+
export type FormRowProps = {
layout?: 'column' | 'split'
title?: React.ReactNode
@@ -27,6 +31,8 @@ export type FormRowProps = {
}
| { type: 'select'; props: FormSelectProps }
| { type: 'emoji'; props: FormEmojiProps }
+ | { type: 'button'; props: LabelButtonProps }
+ | { type: 'node'; element: React.ReactNode }
)[]
}
@@ -66,7 +72,13 @@ const Form: AppComponent = ({
) : item.type === 'emoji' ? (
- ) : null}
+ ) : item.type === 'button' ? (
+
+ {item.props.label}
+
+ ) : (
+ item.element
+ )}
))}
@@ -120,12 +132,14 @@ const Container = styled.form`
align-items: stretch;
}
- .form__row__item--emoji {
+ .form__row__item--emoji,
+ .form__row__item--button {
flex: 0 0 auto;
}
- .form__row__item:not(.form__row__item--emoji),
- .form__row__item:not(.form__row__item--emoji) > * {
+ .form__row__item:not(.form__row__item--emoji):not(.form__row__item--button),
+ .form__row__item:not(.form__row__item--emoji):not(.form__row__item--button)
+ > * {
flex: 1 1 auto;
}
From c79087c9dc9bf219369197ce0a4b34e496651ee5 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 08:33:23 +0900
Subject: [PATCH 64/91] simple select
---
.../molecules/TeamInvitesSection.tsx | 21 ++-----
.../molecules/Form/atoms/FormSelect.tsx | 57 +++++++++++++++++--
.../components/molecules/Form/index.tsx | 9 ++-
3 files changed, 65 insertions(+), 22 deletions(-)
diff --git a/src/cloud/components/molecules/TeamInvitesSection.tsx b/src/cloud/components/molecules/TeamInvitesSection.tsx
index 640e227ffd..027ba7c37d 100644
--- a/src/cloud/components/molecules/TeamInvitesSection.tsx
+++ b/src/cloud/components/molecules/TeamInvitesSection.tsx
@@ -21,7 +21,6 @@ import ErrorBlock from '../atoms/ErrorBlock'
import { SerializedUserTeamPermissions } from '../../interfaces/db/userTeamPermissions'
import Flexbox from '../atoms/Flexbox'
import Form from '../../../shared/components/molecules/Form'
-import { FormSelectOption } from '../../../shared/components/molecules/Form/atoms/FormSelect'
interface TeamInvitesSectionProps {
userPermissions: SerializedUserTeamPermissions
@@ -128,12 +127,12 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
)
const selectRole = useCallback(
- (option: FormSelectOption) => {
+ (option: string) => {
if (userPermissions.role !== 'admin') {
return
}
- setRole(option.value as TeamPermissionType)
+ setRole(option as TeamPermissionType)
},
[setRole, userPermissions]
)
@@ -158,21 +157,13 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
},
},
{
- type: 'select',
+ type: 'select--string',
+
props: {
- value: {
- label: role,
- value: role,
- },
+ value: role,
onChange: selectRole,
isDisabled: userPermissions.role !== 'admin',
- options: [
- {
- label: 'admin',
- value: 'admin',
- },
- { label: 'member', value: 'member' },
- ],
+ options: ['admin', 'member'],
},
},
{
diff --git a/src/shared/components/molecules/Form/atoms/FormSelect.tsx b/src/shared/components/molecules/Form/atoms/FormSelect.tsx
index 9fbbbc4fed..01c454777f 100644
--- a/src/shared/components/molecules/Form/atoms/FormSelect.tsx
+++ b/src/shared/components/molecules/Form/atoms/FormSelect.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react'
+import React, { useCallback, useMemo, useState } from 'react'
import Select from 'react-select'
import cc from 'classcat'
import styled from '../../../../lib/styled'
@@ -8,11 +8,8 @@ export interface FormSelectOption {
value: string
}
-export interface FormSelectProps {
+interface FormSelectCommonProps {
id?: string
- options: FormSelectOption[]
- value?: FormSelectOption
- onChange: (val: any) => void
closeMenuOnSelect?: boolean
className?: string
isDisabled?: boolean
@@ -24,6 +21,20 @@ export interface FormSelectProps {
onMenuOpen?: () => void
}
+interface StandardFormSelectOptions {
+ value?: FormSelectOption
+ options: FormSelectOption[]
+ onChange: (val: any) => void
+}
+
+interface SimpleFormSelectOptions {
+ value: string
+ options: string[]
+ onChange: (val: string) => void
+}
+
+export type FormSelectProps = FormSelectCommonProps & StandardFormSelectOptions
+
const FormSelect = ({
id,
options,
@@ -38,7 +49,7 @@ const FormSelect = ({
name,
filterOption,
onMenuOpen,
-}: FormSelectProps) => {
+}: FormSelectProps & StandardFormSelectOptions) => {
const [focused, setFocused] = useState(false)
return (
@@ -69,6 +80,40 @@ const FormSelect = ({
)
}
+export type SimpleFormSelectProps = FormSelectCommonProps &
+ SimpleFormSelectOptions
+export const SimpleFormSelect = ({
+ options,
+ value,
+ onChange,
+ ...props
+}: SimpleFormSelectProps) => {
+ const convertedOptions = useMemo(() => {
+ return options.map((opt) => {
+ return {
+ label: opt,
+ value: opt,
+ }
+ })
+ }, [options])
+
+ const onSelectChange = useCallback(
+ (val: FormSelectOption) => {
+ onChange(val.value)
+ },
+ [onChange]
+ )
+
+ return (
+
+ )
+}
+
const Container = styled.div`
.form__select .form__select__indicator-separator {
width: 0;
diff --git a/src/shared/components/molecules/Form/index.tsx b/src/shared/components/molecules/Form/index.tsx
index c472c3b472..a1d1a3effe 100644
--- a/src/shared/components/molecules/Form/index.tsx
+++ b/src/shared/components/molecules/Form/index.tsx
@@ -2,7 +2,11 @@ import React, { useState } from 'react'
import styled from '../../../lib/styled'
import { LoadingButton, ButtonProps } from '../../atoms/Button'
import FormInput, { FormInputProps } from './atoms/FormInput'
-import FormSelect, { FormSelectProps } from './atoms/FormSelect'
+import FormSelect, {
+ FormSelectProps,
+ SimpleFormSelect,
+ SimpleFormSelectProps,
+} from './atoms/FormSelect'
import cc from 'classcat'
import { AppComponent } from '../../../lib/types'
import FormEmoji, { FormEmojiProps } from './atoms/FormEmoji'
@@ -30,6 +34,7 @@ export type FormRowProps = {
props: FormInputProps & { ref?: React.Ref }
}
| { type: 'select'; props: FormSelectProps }
+ | { type: 'select--string'; props: SimpleFormSelectProps }
| { type: 'emoji'; props: FormEmojiProps }
| { type: 'button'; props: LabelButtonProps }
| { type: 'node'; element: React.ReactNode }
@@ -70,6 +75,8 @@ const Form: AppComponent = ({
) : item.type === 'select' ? (
+ ) : item.type === 'select--string' ? (
+
) : item.type === 'emoji' ? (
) : item.type === 'button' ? (
From 45d0c4fb12be11ed53281d14d7fb4efa8d35867d Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 08:35:14 +0900
Subject: [PATCH 65/91] optional onSubmit
---
src/shared/components/molecules/Form/index.tsx | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/shared/components/molecules/Form/index.tsx b/src/shared/components/molecules/Form/index.tsx
index a1d1a3effe..35b16df6ef 100644
--- a/src/shared/components/molecules/Form/index.tsx
+++ b/src/shared/components/molecules/Form/index.tsx
@@ -13,8 +13,7 @@ import FormEmoji, { FormEmojiProps } from './atoms/FormEmoji'
interface FormProps {
rows: FormRowProps[]
- onSubmit: React.FormEventHandler
-
+ onSubmit?: React.FormEventHandler
submitButton?: LabelButtonProps
onCancel?: () => void
}
@@ -52,6 +51,10 @@ const Form: AppComponent = ({
return (
{
+ if (onSubmit == null) {
+ return
+ }
+
event.preventDefault()
setSubmitState(true)
new Promise(() => onSubmit(event)).finally(() => setSubmitState(false))
From 2ae12fb4f35feeebfbe0546dedcfa2c81cc6b9c3 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 09:45:15 +0900
Subject: [PATCH 66/91] preferences, layout and overflow, typo
---
.../molecules/TeamInvitesSection.tsx | 3 +-
.../organisms/Subscription/PlanTables.tsx | 4 +-
.../organisms/settings/SettingsComponent.tsx | 7 +-
.../settings/UserPreferencesForm.tsx | 244 +++++++++---------
src/cloud/lib/hooks/useCloudUI.tsx | 2 +-
.../molecules/Form/atoms/FormRow.tsx | 0
.../molecules/Form/atoms/FormSelect.tsx | 3 +-
.../components/molecules/Form/index.tsx | 103 +-------
.../molecules/Form/layouts/FormRow.tsx | 107 ++++++++
.../components/organisms/EmojiInputForm.tsx | 3 +-
.../organisms/Settings/atoms/SettingMain.tsx | 9 -
.../Settings/atoms/SettingTabContent.tsx | 40 ++-
.../components/organisms/Settings/index.tsx | 7 +
13 files changed, 273 insertions(+), 259 deletions(-)
delete mode 100644 src/shared/components/molecules/Form/atoms/FormRow.tsx
create mode 100644 src/shared/components/molecules/Form/layouts/FormRow.tsx
delete mode 100644 src/shared/components/organisms/Settings/atoms/SettingMain.tsx
diff --git a/src/cloud/components/molecules/TeamInvitesSection.tsx b/src/cloud/components/molecules/TeamInvitesSection.tsx
index 027ba7c37d..8baffcfdc3 100644
--- a/src/cloud/components/molecules/TeamInvitesSection.tsx
+++ b/src/cloud/components/molecules/TeamInvitesSection.tsx
@@ -158,7 +158,6 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
},
{
type: 'select--string',
-
props: {
value: role,
onChange: selectRole,
@@ -176,7 +175,7 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
],
},
]}
- >
+ />
{role === 'admin' ? (
Admins can handle billing, remove or promote/demote members.
diff --git a/src/cloud/components/organisms/Subscription/PlanTables.tsx b/src/cloud/components/organisms/Subscription/PlanTables.tsx
index 56bbb80b6b..fdec200a6d 100644
--- a/src/cloud/components/organisms/Subscription/PlanTables.tsx
+++ b/src/cloud/components/organisms/Subscription/PlanTables.tsx
@@ -49,8 +49,8 @@ const PlanTables = ({
const trialEndDate = new Date(subscription.currentPeriodEnd * 1000)
return (
- ✓ In free trial ({' '}
- {formatDistanceToNow(trialEndDate, { includeSeconds: false })} left )
+ ✓ In free trial (
+ {formatDistanceToNow(trialEndDate, { includeSeconds: false })} left)
)
}
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index 07b2a5c612..c8f2a9218c 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -27,7 +27,6 @@ import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import Settings from '../../../../shared/components/organisms/Settings'
import SettingSidenavHeader from '../../../../shared/components/organisms/Settings/molecules/SettingSidenavHeader'
import SettingSidenav from '../../../../shared/components/organisms/Settings/atoms/SettingSidenav'
-import SettingMain from '../../../../shared/components/organisms/Settings/atoms/SettingMain'
import SettingTabButton from '../../../../shared/components/organisms/Settings/atoms/SettingTabButton'
import Icon from '../../../../shared/components/atoms/Icon'
import SettingCloseButton from '../../../../shared/components/organisms/Settings/atoms/SettingCloseButton'
@@ -199,7 +198,7 @@ const SettingsComponent = () => {
}
content={
-
+
{content}
{
>
-
+
}
- >
+ />
)
}
diff --git a/src/cloud/components/organisms/settings/UserPreferencesForm.tsx b/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
index 33f4c1be46..1ae521e317 100644
--- a/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
+++ b/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
@@ -10,76 +10,79 @@ import {
GeneralEditorIndentSize,
} from '../../../lib/stores/settings'
import { useTranslation } from 'react-i18next'
-import { SelectChangeEventHandler } from '../../../lib/utils/events'
import { trackEvent } from '../../../api/track'
import { MixpanelActionTrackTypes } from '../../../interfaces/analytics/mixpanel'
-import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
+import Form from '../../../../shared/components/molecules/Form'
+import FormSelect, {
+ FormSelectOption,
+ SimpleFormSelect,
+} from '../../../../shared/components/molecules/Form/atoms/FormSelect'
+import FormRow from '../../../../shared/components/molecules/Form/layouts/FormRow'
const UserPreferencesForm = () => {
const { settings, setSettings } = useSettings()
const { t } = useTranslation()
- const selectTheme: SelectChangeEventHandler = useCallback(
- (event) => {
+ const selectTheme = useCallback(
+ (formOption: FormSelectOption) => {
setSettings({
- 'general.theme': event.target.value as GeneralThemeOptions,
+ 'general.theme': formOption.value as GeneralThemeOptions,
})
trackEvent(MixpanelActionTrackTypes.ThemeChangeApp, {
- theme: event.target.value,
+ theme: formOption.value,
})
},
[setSettings]
)
- const selectEditorTheme: SelectChangeEventHandler = useCallback(
- (event) => {
+ const selectEditorTheme = useCallback(
+ (value: string) => {
setSettings({
- 'general.editorTheme': event.target.value as CodeMirrorEditorTheme,
+ 'general.editorTheme': value as CodeMirrorEditorTheme,
})
trackEvent(MixpanelActionTrackTypes.ThemeChangeEditor, {
- theme: event.target.value,
+ theme: value,
})
},
[setSettings]
)
- const selectCodeBlockTheme: SelectChangeEventHandler = useCallback(
- (event) => {
+ const selectCodeBlockTheme = useCallback(
+ (value: string) => {
setSettings({
- 'general.codeBlockTheme': event.target.value as CodeMirrorEditorTheme,
+ 'general.codeBlockTheme': value as CodeMirrorEditorTheme,
})
trackEvent(MixpanelActionTrackTypes.ThemeChangeCodeblock, {
- theme: event.target.value,
+ theme: value,
})
},
[setSettings]
)
- const selectEditorKeyMap: SelectChangeEventHandler = useCallback(
- (event) => {
+ const selectEditorKeyMap = useCallback(
+ (value: string) => {
setSettings({
- 'general.editorKeyMap': event.target.value as CodeMirrorKeyMap,
+ 'general.editorKeyMap': value as CodeMirrorKeyMap,
})
},
[setSettings]
)
- const selectIndentType: SelectChangeEventHandler = useCallback(
- (event) => {
+ const selectIndentType = useCallback(
+ (value: string) => {
setSettings({
- 'general.editorIndentType': event.target
- .value as GeneralEditorIndentType,
+ 'general.editorIndentType': value as GeneralEditorIndentType,
})
},
[setSettings]
)
- const selectIndentSize: SelectChangeEventHandler = useCallback(
- (event) => {
+ const selectIndentSize = useCallback(
+ (value: string) => {
setSettings({
'general.editorIndentSize': parseInt(
- event.target.value,
+ value,
10
) as GeneralEditorIndentSize,
})
@@ -88,101 +91,104 @@ const UserPreferencesForm = () => {
)
return (
- <>
-
-
- {t('settings.light')}
- {t('settings.dark')}
- >
- }
- >
-
-
-
-
- {codeMirrorEditorThemes.map((val) => (
-
- {val}
-
- ))}
- >
- }
- >
-
-
-
-
- {codeMirrorEditorThemes.map((val) => (
-
- {val}
-
- ))}
- >
- }
- >
-
-
-
-
- {codeMirrorKeyMap.map((val) => (
-
- {val}
-
- ))}
- >
- }
- >
-
-
-
-
- Spaces
- Tab
- >
- }
- >
-
-
-
-
- 8
- 4
- 2
- >
- }
- >
-
- >
+
+ ),
+ },
+ ],
+ },
+ {
+ title: t('settings.editorTheme'),
+ items: [
+ {
+ type: 'select--string',
+ props: {
+ options: codeMirrorEditorThemes,
+ value: settings['general.editorTheme'],
+ onChange: selectEditorTheme,
+ },
+ },
+ ],
+ },
+ {
+ title: t('settings.codeblockTheme'),
+ items: [
+ {
+ type: 'select--string',
+ props: {
+ options: codeMirrorEditorThemes,
+ value: settings['general.codeBlockTheme'],
+ onChange: selectCodeBlockTheme,
+ },
+ },
+ ],
+ },
+ {
+ title: t('settings.editorKeyMap'),
+ items: [
+ {
+ type: 'select--string',
+ props: {
+ options: codeMirrorKeyMap,
+ value: settings['general.editorKeyMap'],
+ onChange: selectEditorKeyMap,
+ },
+ },
+ ],
+ },
+ {
+ title: 'Editor Indent Type',
+ items: [
+ {
+ type: 'node',
+ element: (
+
+ ),
+ },
+ ],
+ },
+ ]}
+ >
+
+
)
}
diff --git a/src/cloud/lib/hooks/useCloudUI.tsx b/src/cloud/lib/hooks/useCloudUI.tsx
index 90b4394abc..b53b03b4ea 100644
--- a/src/cloud/lib/hooks/useCloudUI.tsx
+++ b/src/cloud/lib/hooks/useCloudUI.tsx
@@ -1,6 +1,6 @@
import { mdiFileDocumentOutline, mdiFolderOutline } from '@mdi/js'
import React, { useCallback } from 'react'
-import { FormRowProps } from '../../../shared/components/molecules/Form'
+import { FormRowProps } from '../../../shared/components/molecules/Form/layouts/FormRow'
import EmojiInputForm from '../../../shared/components/organisms/EmojiInputForm'
import { DialogIconTypes, useDialog } from '../../../shared/lib/stores/dialog'
import { useModal } from '../../../shared/lib/stores/modal'
diff --git a/src/shared/components/molecules/Form/atoms/FormRow.tsx b/src/shared/components/molecules/Form/atoms/FormRow.tsx
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/shared/components/molecules/Form/atoms/FormSelect.tsx b/src/shared/components/molecules/Form/atoms/FormSelect.tsx
index 01c454777f..ec0622ce6c 100644
--- a/src/shared/components/molecules/Form/atoms/FormSelect.tsx
+++ b/src/shared/components/molecules/Form/atoms/FormSelect.tsx
@@ -29,7 +29,7 @@ interface StandardFormSelectOptions {
interface SimpleFormSelectOptions {
value: string
- options: string[]
+ options: readonly string[]
onChange: (val: string) => void
}
@@ -178,6 +178,7 @@ const Container = styled.div`
.form__select .form__select__menu {
background-color: ${({ theme }) => theme.colors.background.primary};
border: 1px solid ${({ theme }) => theme.colors.border.main};
+ overflow-y: visible !important;
}
.form__select .form__select__option {
diff --git a/src/shared/components/molecules/Form/index.tsx b/src/shared/components/molecules/Form/index.tsx
index 35b16df6ef..b14d4f65aa 100644
--- a/src/shared/components/molecules/Form/index.tsx
+++ b/src/shared/components/molecules/Form/index.tsx
@@ -1,45 +1,17 @@
import React, { useState } from 'react'
import styled from '../../../lib/styled'
-import { LoadingButton, ButtonProps } from '../../atoms/Button'
-import FormInput, { FormInputProps } from './atoms/FormInput'
-import FormSelect, {
- FormSelectProps,
- SimpleFormSelect,
- SimpleFormSelectProps,
-} from './atoms/FormSelect'
+import { LoadingButton } from '../../atoms/Button'
import cc from 'classcat'
import { AppComponent } from '../../../lib/types'
-import FormEmoji, { FormEmojiProps } from './atoms/FormEmoji'
+import FormRow, { FormRowProps, FormRowButtonProps } from './layouts/FormRow'
interface FormProps {
rows: FormRowProps[]
onSubmit?: React.FormEventHandler
- submitButton?: LabelButtonProps
+ submitButton?: FormRowButtonProps
onCancel?: () => void
}
-type LabelButtonProps = ButtonProps & {
- label: React.ReactNode
- spinning?: boolean
-}
-
-export type FormRowProps = {
- layout?: 'column' | 'split'
- title?: React.ReactNode
- description?: React.ReactNode
- items?: (
- | {
- type: 'input'
- props: FormInputProps & { ref?: React.Ref }
- }
- | { type: 'select'; props: FormSelectProps }
- | { type: 'select--string'; props: SimpleFormSelectProps }
- | { type: 'emoji'; props: FormEmojiProps }
- | { type: 'button'; props: LabelButtonProps }
- | { type: 'node'; element: React.ReactNode }
- )[]
-}
-
const Form: AppComponent = ({
onSubmit,
rows,
@@ -62,42 +34,7 @@ const Form: AppComponent = ({
className={cc(['form', className])}
>
{rows.map((row, i) => {
- return (
-
- {row.title != null && (
-
{row.title}
- )}
- {row.items != null && (
-
- {row.items.map((item, k) => (
-
- {item.type === 'input' ? (
-
- ) : item.type === 'select' ? (
-
- ) : item.type === 'select--string' ? (
-
- ) : item.type === 'emoji' ? (
-
- ) : item.type === 'button' ? (
-
- {item.props.label}
-
- ) : (
- item.element
- )}
-
- ))}
-
- )}
- {row.description != null && (
-
{row.description}
- )}
-
- )
+ return
})}
{children}
{submitButton != null && (
@@ -121,39 +58,7 @@ export default Form
const Container = styled.form`
font-size: ${({ theme }) => theme.sizes.fonts.df}px;
- .form__row__description {
- color: ${({ theme }) => theme.colors.text.subtle};
- }
-
.form__row + .form__row {
margin-top: ${({ theme }) => theme.sizes.spaces.df}px;
}
-
- .form__row__items {
- display: flex;
- flex-direction: row;
- flex-wrap: nowrap;
- align-items: stretch;
- justify-content: space-between;
- }
-
- .form__row__item {
- display: flex;
- align-items: stretch;
- }
-
- .form__row__item--emoji,
- .form__row__item--button {
- flex: 0 0 auto;
- }
-
- .form__row__item:not(.form__row__item--emoji):not(.form__row__item--button),
- .form__row__item:not(.form__row__item--emoji):not(.form__row__item--button)
- > * {
- flex: 1 1 auto;
- }
-
- .form__row__item + .form__row__item {
- margin-left: ${({ theme }) => theme.sizes.spaces.df}px;
- }
`
diff --git a/src/shared/components/molecules/Form/layouts/FormRow.tsx b/src/shared/components/molecules/Form/layouts/FormRow.tsx
new file mode 100644
index 0000000000..6e2e616aaa
--- /dev/null
+++ b/src/shared/components/molecules/Form/layouts/FormRow.tsx
@@ -0,0 +1,107 @@
+import React from 'react'
+import styled from '../../../../lib/styled'
+import { AppComponent } from '../../../../lib/types'
+import { ButtonProps, LoadingButton } from '../../../atoms/Button'
+import FormEmoji, { FormEmojiProps } from '../atoms/FormEmoji'
+import FormInput, { FormInputProps } from '../atoms/FormInput'
+import FormSelect, {
+ FormSelectProps,
+ SimpleFormSelect,
+ SimpleFormSelectProps,
+} from '../atoms/FormSelect'
+import cc from 'classcat'
+
+export type FormRowButtonProps = ButtonProps & {
+ label: React.ReactNode
+ spinning?: boolean
+}
+
+export type FormRowProps = {
+ layout?: 'column' | 'split'
+ title?: React.ReactNode
+ description?: React.ReactNode
+ items?: (
+ | {
+ type: 'input'
+ props: FormInputProps & { ref?: React.Ref }
+ }
+ | { type: 'select'; props: FormSelectProps }
+ | { type: 'select--string'; props: SimpleFormSelectProps }
+ | { type: 'emoji'; props: FormEmojiProps }
+ | { type: 'button'; props: FormRowButtonProps }
+ | { type: 'node'; element: React.ReactNode }
+ )[]
+}
+
+const FormRow: AppComponent<{ row: FormRowProps }> = ({ row, className }) => {
+ return (
+
+ {row.title != null && {row.title}
}
+ {row.items != null && (
+
+ {row.items.map((item, k) => (
+
+ {item.type === 'input' ? (
+
+ ) : item.type === 'select' ? (
+
+ ) : item.type === 'select--string' ? (
+
+ ) : item.type === 'emoji' ? (
+
+ ) : item.type === 'button' ? (
+
+ {item.props.label}
+
+ ) : (
+ item.element
+ )}
+
+ ))}
+
+ )}
+ {row.description != null && (
+ {row.description}
+ )}
+
+ )
+}
+
+const Container = styled.div`
+ .form__row__description {
+ color: ${({ theme }) => theme.colors.text.subtle};
+ }
+
+ .form__row__items {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ align-items: stretch;
+ justify-content: space-between;
+ }
+
+ .form__row__item {
+ display: flex;
+ align-items: stretch;
+ }
+
+ .form__row__item--emoji,
+ .form__row__item--button {
+ flex: 0 0 auto;
+ }
+
+ .form__row__item:not(.form__row__item--emoji):not(.form__row__item--button),
+ .form__row__item:not(.form__row__item--emoji):not(.form__row__item--button)
+ > * {
+ flex: 1 1 auto;
+ }
+
+ .form__row__item + .form__row__item {
+ margin-left: ${({ theme }) => theme.sizes.spaces.df}px;
+ }
+`
+
+export default FormRow
diff --git a/src/shared/components/organisms/EmojiInputForm.tsx b/src/shared/components/organisms/EmojiInputForm.tsx
index 9f41bca52b..f28ddf49e0 100644
--- a/src/shared/components/organisms/EmojiInputForm.tsx
+++ b/src/shared/components/organisms/EmojiInputForm.tsx
@@ -1,7 +1,8 @@
import React, { useRef, useState } from 'react'
import { useEffectOnce } from 'react-use'
import { ButtonProps } from '../atoms/Button'
-import Form, { FormRowProps } from '../molecules/Form'
+import Form from '../molecules/Form'
+import { FormRowProps } from '../molecules/Form/layouts/FormRow'
interface EmojiInputFormProps {
prevRows?: FormRowProps[]
diff --git a/src/shared/components/organisms/Settings/atoms/SettingMain.tsx b/src/shared/components/organisms/Settings/atoms/SettingMain.tsx
deleted file mode 100644
index fd8ae7695d..0000000000
--- a/src/shared/components/organisms/Settings/atoms/SettingMain.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import styled from '../../../../../lib/styled'
-
-const SettingMain = styled.div`
- flex: 1;
- position: relative;
- overflow: hidden auto;
-`
-
-export default SettingMain
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
index 097f74ffdf..0509f41856 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
@@ -14,61 +14,59 @@ const SettingTabContent = ({
body,
footer,
}: SettingTabContentProps) => (
-
-
-
-
-
{title}
-
{description}
+
+
+
+
+
{title}
+
+ {description}
+
-
{body}
-
{footer}
+
{body}
+
{footer}
)
const Container = styled.div`
- display: flex;
- flex-direction: column;
+ display: block;
width: 100%;
- height: 100%;
padding-top: ${({ theme }) => theme.sizes.spaces.xl}px;
- .tab-content__scrollable {
- flex: 1 1 auto;
+ .setting__tab__content__scrollable {
width: 100%;
padding: ${({ theme }) => theme.sizes.spaces.xl}px
${({ theme }) => theme.sizes.spaces.md}px;
- overflow: hidden auto;
}
- .tab-content__container {
+ .setting__tab__content__container {
max-width: 700px;
margin: 0 auto;
}
- .tab-content__header {
+ .setting__tab__content__header {
margin-bottom: ${({ theme }) => theme.sizes.spaces.l}px;
padding-bottom: ${({ theme }) => theme.sizes.spaces.l}px;
border-bottom: 1px solid ${({ theme }) => theme.colors.border.main};
}
- .tab-content__header__title {
+ .setting__tab__content__header__title {
margin-top: 0;
margin-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px;
font-size: ${({ theme }) => theme.sizes.fonts.l}px;
font-weight: normal;
}
- .tab-content__header__description {
+ .setting__tab__content__header__description {
margin-bottom: 0;
color: ${({ theme }) => theme.colors.text.subtle};
font-size: ${({ theme }) => theme.sizes.fonts.df}px;
}
- .tab-content__body,
- .tab-content__footer {
+ .setting__tab__content__body,
+ .setting__tab__content__footer {
h2 {
font-size: ${({ theme }) => theme.sizes.fonts.md}px;
font-weight: normal;
@@ -83,7 +81,7 @@ const Container = styled.div`
}
}
- .tab-content__body {
+ .setting__tab__content__body {
section {
margin: ${({ theme }) => theme.sizes.spaces.md}px 0;
}
diff --git a/src/shared/components/organisms/Settings/index.tsx b/src/shared/components/organisms/Settings/index.tsx
index a5e84fc7d3..d548d3a365 100644
--- a/src/shared/components/organisms/Settings/index.tsx
+++ b/src/shared/components/organisms/Settings/index.tsx
@@ -51,8 +51,15 @@ const Container = styled.div`
.settings__content {
flex: 1 1 100%;
min-width: 0;
+ display: block;
+ height: 100vh;
overflow: auto;
}
+
+ .settings__content__wrapper {
+ width: 100%;
+ height: auto;
+ }
`
export default Settings
From 720191a4393388f2b8ed4d832ce708321155f0f0 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 11:17:03 +0900
Subject: [PATCH 67/91] fix personal info tab
---
.../molecules/TeamInvitesSection.tsx | 1 +
.../organisms/settings/MembersTab.tsx | 42 +++---
.../organisms/settings/PersonalInfoTab.tsx | 131 +++++++-----------
.../organisms/settings/TeamInfoTab.tsx | 2 -
src/shared/components/atoms/Button.tsx | 4 -
.../molecules/Form/atoms/FormEmoji.tsx | 3 +-
.../molecules/Form/atoms/FormImage.tsx | 115 +++++++++++++++
.../molecules/Form/atoms/FormInput.tsx | 3 +-
.../molecules/Form/atoms/FormSelect.tsx | 31 +++--
.../components/molecules/Form/index.tsx | 8 +-
.../molecules/Form/layouts/FormRow.tsx | 9 ++
.../Settings/atoms/SettingDivider.tsx | 11 --
.../Settings/atoms/SettingTabContent.tsx | 10 +-
.../Settings/molecules/SettingIconInput.tsx | 65 ---------
src/shared/lib/styled/styleFunctions.ts | 5 +
15 files changed, 240 insertions(+), 200 deletions(-)
create mode 100644 src/shared/components/molecules/Form/atoms/FormImage.tsx
delete mode 100644 src/shared/components/organisms/Settings/atoms/SettingDivider.tsx
delete mode 100644 src/shared/components/organisms/Settings/molecules/SettingIconInput.tsx
diff --git a/src/cloud/components/molecules/TeamInvitesSection.tsx b/src/cloud/components/molecules/TeamInvitesSection.tsx
index 8baffcfdc3..2c4dd2a993 100644
--- a/src/cloud/components/molecules/TeamInvitesSection.tsx
+++ b/src/cloud/components/molecules/TeamInvitesSection.tsx
@@ -170,6 +170,7 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
props: {
type: 'submit',
label: 'Send',
+ disabled: sending,
},
},
],
diff --git a/src/cloud/components/organisms/settings/MembersTab.tsx b/src/cloud/components/organisms/settings/MembersTab.tsx
index c98562feab..6d9afd245c 100644
--- a/src/cloud/components/organisms/settings/MembersTab.tsx
+++ b/src/cloud/components/organisms/settings/MembersTab.tsx
@@ -40,11 +40,11 @@ import SettingsTeamForm from '../../molecules/SettingsTeamForm'
import { guestsPerMember } from '../../../lib/subscription'
import { useToast } from '../../../../shared/lib/stores/toast'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
-import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
import Button from '../../../../shared/components/atoms/Button'
import Flexbox from '../../../../shared/components/atoms/Flexbox'
import SettingTabSelector from '../../../../shared/components/organisms/Settings/atoms/SettingTabSelector'
import { ExternalLink } from '../../../../shared/components/atoms/Link'
+import { SimpleFormSelect } from '../../../../shared/components/molecules/Form/atoms/FormSelect'
const MembersTab = () => {
const { t } = useTranslation()
@@ -219,12 +219,10 @@ const MembersTab = () => {
const changePermissionsRole = useCallback(
async (
- event: React.ChangeEvent,
+ targetedRole,
userPermissions,
targetedPermissions: SerializedUserTeamPermissions
) => {
- event.preventDefault()
- const targetedRole = event.target.value
if (
team == null ||
userPermissions.role !== 'admin' ||
@@ -536,32 +534,22 @@ const MembersTab = () => {
}}
/>
) : (
-
+ onChange={(value: string) =>
changePermissionsRole(
- e,
+ value,
currentUserPermissions,
permission
)
}
- style={{
- width: 'auto',
- minWidth: 'initial',
- height: 24,
- marginRight: 16,
- }}
- disabled={
+ isDisabled={
!currentUserIsAdmin ||
targetPermissionsAreUsersOwn
}
- options={
- <>
- admin
- member
- >
- }
- >
+ options={['admin', 'member']}
+ />
)}
{(targetPermissionsAreUsersOwn ||
currentUserIsAdmin) && (
@@ -737,11 +725,13 @@ const StyledMembersTable = styled.table`
.user-action {
position: relative;
- select {
- padding-left: 0;
- padding-right: ${({ theme }) => theme.space.small}px;
- background-color: transparent;
- border: transparent;
+
+ .form__select__wrapper {
+ flex: 1 0 auto;
+ }
+
+ .form__select .form__select__control {
+ /* border: transparent; */
}
}
diff --git a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
index d38a025067..e551455782 100644
--- a/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/PersonalInfoTab.tsx
@@ -3,19 +3,13 @@ import { useTranslation } from 'react-i18next'
import { useGlobalData } from '../../../lib/stores/globalData'
import { saveUserInfo, updateUserIcon } from '../../../api/users'
import { buildIconUrl } from '../../../api/files'
-import { Spinner } from '../../atoms/Spinner'
import { useSettings } from '../../../lib/stores/settings'
import AccountLink from '../../atoms/Link/AccountLink'
-import { SelectChangeEventHandler } from '../../../lib/utils/events'
import { UserEmailNotificationType } from '../../../interfaces/db/userSettings'
import { saveUserSettings } from '../../../api/users/settings'
import { useToast } from '../../../../shared/lib/stores/toast'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
-import SettingInput from '../../../../shared/components/organisms/Settings/atoms/SettingInput'
-import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
-import Button from '../../../../shared/components/atoms/Button'
-import SettingDivider from '../../../../shared/components/organisms/Settings/atoms/SettingDivider'
-import SettingIconInput from '../../../../shared/components/organisms/Settings/molecules/SettingIconInput'
+import Form from '../../../../shared/components/molecules/Form'
const PersonalInfoTab = () => {
const {
@@ -92,19 +86,19 @@ const PersonalInfoTab = () => {
return buildIconUrl(currentUser.icon.location)
}, [currentUser])
- const selectCurrentEmailNotifications: SelectChangeEventHandler = useCallback(
- (event) => {
- let value: UserEmailNotificationType | 'never'
- switch (event.target.value) {
+ const selectCurrentEmailNotifications = useCallback(
+ (value: string | 'never') => {
+ let targetedValue: UserEmailNotificationType | 'never'
+ switch (value) {
case 'daily':
case 'weekly':
- value = event.target.value
+ targetedValue = value
break
case 'never':
default:
- value = 'never'
+ targetedValue = 'never'
}
- setCurrentEmailNotifications(value)
+ setCurrentEmailNotifications(targetedValue)
},
[]
)
@@ -114,73 +108,54 @@ const PersonalInfoTab = () => {
title={t('settings.personalInfo')}
description={'Manage your Boost Note profile.'}
body={
- <>
- {currentUser != null && (
- <>
-
-
- >
- )}
-
- {currentUser != null && (
-
-
-
- Daily
-
-
- Weekly
-
-
- Never
-
- >
- }
- >
-
- )}
-
-
-
- {updating ? (
-
- ) : (
- t('general.update')
- )}
-
-
- >
+ currentUser == null ? null : (
+
+ )
}
footer={
<>
-
{t('settings.account.delete')}
You may delete your account at any time, note that this is
diff --git a/src/cloud/components/organisms/settings/TeamInfoTab.tsx b/src/cloud/components/organisms/settings/TeamInfoTab.tsx
index 70ee2670c4..2a94962377 100644
--- a/src/cloud/components/organisms/settings/TeamInfoTab.tsx
+++ b/src/cloud/components/organisms/settings/TeamInfoTab.tsx
@@ -6,7 +6,6 @@ import { useSettings } from '../../../lib/stores/settings'
import TeamLink from '../../atoms/Link/TeamLink'
import SettingsTeamForm from '../../molecules/SettingsTeamForm'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
-import SettingDivider from '../../../../shared/components/organisms/Settings/atoms/SettingDivider'
const TeamInfoTab = () => {
const { team, currentUserPermissions } = usePage()
@@ -25,7 +24,6 @@ const TeamInfoTab = () => {
return (
<>
-
Delete Space
diff --git a/src/shared/components/atoms/Button.tsx b/src/shared/components/atoms/Button.tsx
index afa2106c93..fcd04239bb 100644
--- a/src/shared/components/atoms/Button.tsx
+++ b/src/shared/components/atoms/Button.tsx
@@ -354,8 +354,4 @@ const StyledButton = styled.button`
&:focus {
box-shadow: 0 0 0 1px ${({ theme }) => theme.colors.variants.info.base};
}
-
- .button__spinner {
- margin-top: 6px;
- }
`
diff --git a/src/shared/components/molecules/Form/atoms/FormEmoji.tsx b/src/shared/components/molecules/Form/atoms/FormEmoji.tsx
index 9748d1cef5..d33f6f403e 100644
--- a/src/shared/components/molecules/Form/atoms/FormEmoji.tsx
+++ b/src/shared/components/molecules/Form/atoms/FormEmoji.tsx
@@ -9,6 +9,7 @@ import styled from '../../../../lib/styled'
import { useEmojiPicker } from '../../../../../cloud/lib/stores/emoji'
import Icon from '../../../atoms/Icon'
import { Emoji } from 'emoji-mart'
+import { formInputHeight } from '../../../../lib/styled/styleFunctions'
export interface FormEmojiProps {
emoji?: string
@@ -95,7 +96,7 @@ const Container = styled.button`
padding: 0 ${({ theme }) => theme.sizes.spaces.sm}px;
border-radius: ${({ theme }) => theme.borders.radius}px;
font-size: ${({ theme }) => theme.sizes.fonts.df}px;
- height: 32px;
+ ${formInputHeight()}
outline: none;
background: none;
border: 1px solid ${({ theme }) => theme.colors.border.main};
diff --git a/src/shared/components/molecules/Form/atoms/FormImage.tsx b/src/shared/components/molecules/Form/atoms/FormImage.tsx
new file mode 100644
index 0000000000..43ddb6b0d0
--- /dev/null
+++ b/src/shared/components/molecules/Form/atoms/FormImage.tsx
@@ -0,0 +1,115 @@
+import React, { useCallback, useState } from 'react'
+import styled from '../../../../lib/styled'
+import { AppComponent } from '../../../../lib/types'
+import cc from 'classcat'
+import Icon from '@mdi/react'
+
+export interface FormImageProps {
+ onChange?: (file: File) => void
+ defaultUrl?: string
+ defaultIcon?: string
+ label?: string
+}
+
+const FormImage: AppComponent = ({
+ className,
+ defaultIcon,
+ defaultUrl,
+ label = 'Select Image...',
+ onChange,
+}) => {
+ const [fileUrl, setFileUrl] = useState(null)
+
+ const changeHandler: React.ChangeEventHandler = useCallback(
+ (event) => {
+ if (
+ event.target != null &&
+ event.target.files != null &&
+ event.target.files.length > 0
+ ) {
+ const file = event.target.files[0]
+ setFileUrl(URL.createObjectURL(file))
+ if (onChange != null) {
+ onChange(file)
+ }
+ }
+ },
+ [onChange]
+ )
+
+ return (
+
+
+ {fileUrl == null && defaultUrl == null && defaultIcon != null ? (
+
+ ) : (
+
+ )}
+
+
+ {label}
+
+
+
+ )
+}
+
+const Container = styled.div`
+ display: flex;
+ align-items: center;
+
+ .form__image__wrapper {
+ width: 90px;
+ height: 90px;
+ }
+
+ .form__image--img {
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
+ background: ${({ theme }) => theme.colors.background.secondary};
+ border: 1px solid ${({ theme }) => theme.colors.border.second};
+ border-radius: 50%;
+ }
+
+ .form__image__label {
+ position: relative;
+ cursor: pointer;
+ margin-left: ${({ theme }) => theme.sizes.spaces.md}px;
+
+ & > span {
+ display: flex;
+ align-items: center;
+ height: 32px;
+ padding: 0 ${({ theme }) => theme.sizes.spaces.md}px;
+ background-color: ${({ theme }) => theme.colors.variants.secondary.base};
+ border-radius: 4px;
+ color: ${({ theme }) => theme.colors.variants.secondary.text};
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+ transition: 200ms background-color;
+
+ &.focus {
+ filter: brightness(103%);
+ }
+ &:hover {
+ filter: brightness(106%);
+ }
+ &:active,
+ &.button__state--active {
+ filter: brightness(112%);
+ }
+ }
+
+ & > input[type='file'] {
+ position: absolute;
+ opacity: 0;
+ height: 0px;
+ width: 0px;
+ }
+ }
+`
+
+export default FormImage
diff --git a/src/shared/components/molecules/Form/atoms/FormInput.tsx b/src/shared/components/molecules/Form/atoms/FormInput.tsx
index 42aaab5018..c7457f426c 100644
--- a/src/shared/components/molecules/Form/atoms/FormInput.tsx
+++ b/src/shared/components/molecules/Form/atoms/FormInput.tsx
@@ -5,6 +5,7 @@ import React, {
} from 'react'
import cc from 'classcat'
import styled from '../../../../lib/styled'
+import { formInputHeight } from '../../../../lib/styled/styleFunctions'
export interface FormInputProps {
type?: 'text' | 'number' | 'email' | 'password'
@@ -98,7 +99,7 @@ const StyledInput = styled.input`
padding: 0 ${({ theme }) => theme.sizes.spaces.sm}px;
border-radius: ${({ theme }) => theme.borders.radius}px;
font-size: ${({ theme }) => theme.sizes.fonts.df}px;
- height: 32px;
+ ${formInputHeight()}
outline: none;
background: none;
border: 1px solid ${({ theme }) => theme.colors.border.main};
diff --git a/src/shared/components/molecules/Form/atoms/FormSelect.tsx b/src/shared/components/molecules/Form/atoms/FormSelect.tsx
index ec0622ce6c..1eaad04da2 100644
--- a/src/shared/components/molecules/Form/atoms/FormSelect.tsx
+++ b/src/shared/components/molecules/Form/atoms/FormSelect.tsx
@@ -2,6 +2,8 @@ import React, { useCallback, useMemo, useState } from 'react'
import Select from 'react-select'
import cc from 'classcat'
import styled from '../../../../lib/styled'
+import { formInputHeight } from '../../../../lib/styled/styleFunctions'
+import { capitalize } from 'lodash'
export interface FormSelectOption {
label: string | React.ReactNode
@@ -52,7 +54,7 @@ const FormSelect = ({
}: FormSelectProps & StandardFormSelectOptions) => {
const [focused, setFocused] = useState(false)
return (
-
+
{
return options.map((opt) => {
return {
- label: opt,
+ label: capitalize(opt),
value: opt,
}
})
@@ -108,7 +110,9 @@ export const SimpleFormSelect = ({
)
@@ -122,24 +126,33 @@ const Container = styled.div`
.form__select .form__select__control,
.form__select .form__select__indicator,
.form__select .form__select__indicators {
- height: 32px;
- min-height: 32px;
+ ${formInputHeight()}
}
.form__select .form__select__control {
width: 100%;
- color: ${({ theme }) => theme.colors.text.subtle};
+ color: ${({ theme }) => theme.colors.text.primary};
border: none;
&.form__select__control--is-focused {
box-shadow: ${({ theme }) => theme.colors.shadow};
}
}
+ .form__select.form__select--disabled {
+ opacity: 0.4;
+ .form__select__single-value,
+ .form__select__value-container,
+ .form__select__dropdown-indicator,
+ .form__select__multi-value__label,
+ .form__select__multi-value__remove {
+ color: ${({ theme }) => theme.colors.text.subtle} !important;
+ }
+ }
+
.form__select .form__select__input {
opacity: inherit;
- color: ${({ theme }) => theme.colors.text.primary};
+ color: ${({ theme }) => theme.colors.text.subtle};
&.form__select__input--is-disabled {
- opacity: 0.6;
}
input {
outline: none !important;
@@ -153,7 +166,7 @@ const Container = styled.div`
.form__select .form__select__dropdown-indicator,
.form__select .form__select__multi-value__label,
.form__select .form__select__multi-value__remove {
- color: ${({ theme }) => theme.colors.text.subtle};
+ color: ${({ theme }) => theme.colors.text.primary};
}
.form__select .form__select__multi-value {
diff --git a/src/shared/components/molecules/Form/index.tsx b/src/shared/components/molecules/Form/index.tsx
index b14d4f65aa..ed5efd8c41 100644
--- a/src/shared/components/molecules/Form/index.tsx
+++ b/src/shared/components/molecules/Form/index.tsx
@@ -29,7 +29,11 @@ const Form: AppComponent = ({
event.preventDefault()
setSubmitState(true)
- new Promise(() => onSubmit(event)).finally(() => setSubmitState(false))
+ new Promise(async (resolve) => {
+ await onSubmit(event)
+ setSubmitState(false)
+ resolve(true)
+ })
}}
className={cc(['form', className])}
>
@@ -59,6 +63,6 @@ const Container = styled.form`
font-size: ${({ theme }) => theme.sizes.fonts.df}px;
.form__row + .form__row {
- margin-top: ${({ theme }) => theme.sizes.spaces.df}px;
+ margin-top: ${({ theme }) => theme.sizes.spaces.md}px;
}
`
diff --git a/src/shared/components/molecules/Form/layouts/FormRow.tsx b/src/shared/components/molecules/Form/layouts/FormRow.tsx
index 6e2e616aaa..4b372d610f 100644
--- a/src/shared/components/molecules/Form/layouts/FormRow.tsx
+++ b/src/shared/components/molecules/Form/layouts/FormRow.tsx
@@ -10,6 +10,7 @@ import FormSelect, {
SimpleFormSelectProps,
} from '../atoms/FormSelect'
import cc from 'classcat'
+import FormImage, { FormImageProps } from '../atoms/FormImage'
export type FormRowButtonProps = ButtonProps & {
label: React.ReactNode
@@ -29,6 +30,7 @@ export type FormRowProps = {
| { type: 'select--string'; props: SimpleFormSelectProps }
| { type: 'emoji'; props: FormEmojiProps }
| { type: 'button'; props: FormRowButtonProps }
+ | { type: 'image'; props: FormImageProps }
| { type: 'node'; element: React.ReactNode }
)[]
}
@@ -50,6 +52,8 @@ const FormRow: AppComponent<{ row: FormRowProps }> = ({ row, className }) => {
) : item.type === 'select--string' ? (
+ ) : item.type === 'image' ? (
+
) : item.type === 'emoji' ? (
) : item.type === 'button' ? (
@@ -75,6 +79,11 @@ const Container = styled.div`
color: ${({ theme }) => theme.colors.text.subtle};
}
+ .form__row__title {
+ filter: brightness(80%);
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
+ }
+
.form__row__items {
display: flex;
flex-direction: row;
diff --git a/src/shared/components/organisms/Settings/atoms/SettingDivider.tsx b/src/shared/components/organisms/Settings/atoms/SettingDivider.tsx
deleted file mode 100644
index ddc5acf07a..0000000000
--- a/src/shared/components/organisms/Settings/atoms/SettingDivider.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import styled from '../../../../lib/styled'
-
-const SettingDivider = styled.div`
- margin-top: ${({ theme }) => theme.sizes.spaces.l}px;
- margin-bottom: ${({ theme }) => theme.sizes.spaces.l}px;
- width: 100%;
- height: 1px;
- background-color: ${({ theme }) => theme.colors.border.main};
-`
-
-export default SettingDivider
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
index 0509f41856..b51950e0c0 100644
--- a/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
+++ b/src/shared/components/organisms/Settings/atoms/SettingTabContent.tsx
@@ -24,7 +24,9 @@ const SettingTabContent = ({
{body}
-
{footer}
+ {footer != null && (
+
{footer}
+ )}
@@ -35,6 +37,12 @@ const Container = styled.div`
width: 100%;
padding-top: ${({ theme }) => theme.sizes.spaces.xl}px;
+ .setting__tab__content__footer {
+ margin-top: ${({ theme }) => theme.sizes.spaces.l}px;
+ padding-top: ${({ theme }) => theme.sizes.spaces.l}px;
+ border-top: 1px solid ${({ theme }) => theme.colors.border.main};
+ }
+
.setting__tab__content__scrollable {
width: 100%;
padding: ${({ theme }) => theme.sizes.spaces.xl}px
diff --git a/src/shared/components/organisms/Settings/molecules/SettingIconInput.tsx b/src/shared/components/organisms/Settings/molecules/SettingIconInput.tsx
deleted file mode 100644
index cbf5f65798..0000000000
--- a/src/shared/components/organisms/Settings/molecules/SettingIconInput.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import React, { useState, useCallback } from 'react'
-import styled from '../../../../lib/styled'
-import SettingIconInputLabel from '../atoms/SettingIconInputLabel'
-
-interface SettingIconInputProps {
- onChange?: (file: File) => void
- defaultUrl?: string
-}
-
-const SettingIconInput = ({ onChange, defaultUrl }: SettingIconInputProps) => {
- const [fileUrl, setFileUrl] = useState(null)
-
- const changeHandler: React.ChangeEventHandler = useCallback(
- (event) => {
- if (
- event.target != null &&
- event.target.files != null &&
- event.target.files.length > 0
- ) {
- const file = event.target.files[0]
- setFileUrl(URL.createObjectURL(file))
- if (onChange != null) {
- onChange(file)
- }
- }
- },
- [onChange]
- )
-
- return (
-
-
-
-
-
- Select Image...
-
-
-
- )
-}
-
-export default SettingIconInput
-
-const Container = styled.div`
- display: flex;
- align-items: center;
-
- .setting__icon-input__img {
- width: 90px;
- height: 90px;
- }
-
- .setting__icon-input__img__content {
- object-fit: cover;
- width: 100%;
- height: 100%;
- background: ${({ theme }) => theme.colors.background.secondary};
- border: 1px solid ${({ theme }) => theme.colors.border.second};
- border-radius: 50%;
- }
-`
diff --git a/src/shared/lib/styled/styleFunctions.ts b/src/shared/lib/styled/styleFunctions.ts
index 07d9cd7f55..a20f4a3d2d 100644
--- a/src/shared/lib/styled/styleFunctions.ts
+++ b/src/shared/lib/styled/styleFunctions.ts
@@ -115,6 +115,11 @@ export const hideScroll = () => `
Form
———————————–———————————–———————————–——–—— */
+export const formInputHeight = () => `
+ height: 32px;
+ min-height: 32px;
+`
+
/* ———————————–———————————–———————————–——–——
Table
———————————–———————————–———————————–——–—— */
From fe72e2c7ab88ec42d818b51b50fb46f011d21c8a Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 11:22:04 +0900
Subject: [PATCH 68/91] fix dom nesting
---
.../components/organisms/settings/MembersTab.tsx | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/cloud/components/organisms/settings/MembersTab.tsx b/src/cloud/components/organisms/settings/MembersTab.tsx
index 6d9afd245c..bbda4d0e60 100644
--- a/src/cloud/components/organisms/settings/MembersTab.tsx
+++ b/src/cloud/components/organisms/settings/MembersTab.tsx
@@ -455,7 +455,9 @@ const MembersTab = () => {
- User
+
+ User
+
@@ -496,8 +498,10 @@ const MembersTab = () => {
- User
- Access Level
+
+ User
+ Access Level
+
{permissions.map((permission) => {
@@ -628,8 +632,10 @@ const MembersTab = () => {
- User
- Access Level
+
+ User
+ Access Level
+
{[...guestsMap.values()].map((guest) => (
From ea209d4459d7f431c1221735e7badb7735e6a555 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 11:47:13 +0900
Subject: [PATCH 69/91] textarea and feedback form
---
.../molecules/AppFeedbackForm/index.tsx | 83 +++++-------
.../molecules/AppFeedbackForm/styled.ts | 45 -------
.../Modal/contents/FeedbackModal.tsx | 8 +-
.../molecules/Form/atoms/FormTextArea.tsx | 123 ++++++++++++++++++
.../molecules/Form/layouts/FormRow.tsx | 7 +
.../components/organisms/Modal/index.tsx | 1 -
.../Settings/atoms/SettingSelect.tsx | 57 --------
.../Settings/atoms/SettingTextarea.tsx | 25 ----
8 files changed, 167 insertions(+), 182 deletions(-)
delete mode 100644 src/cloud/components/molecules/AppFeedbackForm/styled.ts
create mode 100644 src/shared/components/molecules/Form/atoms/FormTextArea.tsx
delete mode 100644 src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
delete mode 100644 src/shared/components/organisms/Settings/atoms/SettingTextarea.tsx
diff --git a/src/cloud/components/molecules/AppFeedbackForm/index.tsx b/src/cloud/components/molecules/AppFeedbackForm/index.tsx
index 9a8a436871..9d683ed47f 100644
--- a/src/cloud/components/molecules/AppFeedbackForm/index.tsx
+++ b/src/cloud/components/molecules/AppFeedbackForm/index.tsx
@@ -1,15 +1,11 @@
import React, { FormEvent, useState, useCallback, useRef } from 'react'
import CustomButton from '../../atoms/buttons/CustomButton'
-import { Spinner } from '../../atoms/Spinner'
-import { StyledAppFeedbackForm } from './styled'
-import { SelectChangeEventHandler } from '../../../lib/utils/events'
import { registerAppFeedback } from '../../../api/users/appfeedback'
import { AppFeedbackTypeOption } from '../../../interfaces/db/userAppFeedback'
import ColoredBlock from '../../atoms/ColoredBlock'
import { useEffectOnce } from 'react-use'
import { useToast } from '../../../../shared/lib/stores/toast'
-import SettingSelect from '../../../../shared/components/organisms/Settings/atoms/SettingSelect'
-import SettingTextarea from '../../../../shared/components/organisms/Settings/atoms/SettingTextarea'
+import Form from '../../../../shared/components/molecules/Form'
const typeOptions: AppFeedbackTypeOption[] = ['Feature Request', 'Bug Report']
@@ -57,13 +53,9 @@ const AppFeedbackForm = () => {
]
)
- const feedbackTypeChangeHandler: SelectChangeEventHandler = useCallback(
- async (event) => {
- event.preventDefault()
- setFeedbackType(event.target.value as AppFeedbackTypeOption)
- },
- []
- )
+ const feedbackTypeChangeHandler = useCallback(async (value: string) => {
+ setFeedbackType(value as AppFeedbackTypeOption)
+ }, [])
const feedbackOnChangeEvent = useCallback(
(event: React.ChangeEvent) => {
@@ -94,41 +86,38 @@ const AppFeedbackForm = () => {
}
return (
-
- Type of feedback
-
- {typeOptions.map((val) => (
-
- {val}
-
- ))}
- >
- }
- >
-
- Free form
-
-
-
-
- {sending ? : 'Send'}
-
-
-
-
+
)
}
diff --git a/src/cloud/components/molecules/AppFeedbackForm/styled.ts b/src/cloud/components/molecules/AppFeedbackForm/styled.ts
deleted file mode 100644
index 796c44fec7..0000000000
--- a/src/cloud/components/molecules/AppFeedbackForm/styled.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import styled from '../../../lib/styled'
-
-export const StyledAppFeedbackForm = styled.form`
- margin: 0 auto;
- color: ${({ theme }) => theme.baseTextColor};
-
- .flex {
- display: flex;
- width: 100%;
- align-items: center;
- }
-
- .row {
- display: block;
- margin: ${({ theme }) => theme.space.medium}px 0
- ${({ theme }) => theme.space.small}px;
- }
-
- .submit-feedback {
- width: 100px;
- border-radius: 2px;
-
- svg {
- color: ${({ theme }) => theme.emphasizedTextColor} !important;
- }
- }
-
- svg.icon {
- top: 0;
- left: 0;
- position: relative !important;
- }
-
- .submit-row {
- display: flex;
- width: 100%;
- justify-content: flex-start;
- align-items: center;
- margin-top: ${({ theme }) => theme.space.xlarge}px;
- }
-
- .clear {
- clear: both;
- }
-`
diff --git a/src/cloud/components/organisms/Modal/contents/FeedbackModal.tsx b/src/cloud/components/organisms/Modal/contents/FeedbackModal.tsx
index 253964188a..45d8da226f 100644
--- a/src/cloud/components/organisms/Modal/contents/FeedbackModal.tsx
+++ b/src/cloud/components/organisms/Modal/contents/FeedbackModal.tsx
@@ -1,14 +1,8 @@
import React from 'react'
-import { ModalContainer } from './styled'
import AppFeedbackForm from '../../../molecules/AppFeedbackForm'
const FeedbackModal = () => {
- return (
-
- Feedback
-
-
- )
+ return
}
export default FeedbackModal
diff --git a/src/shared/components/molecules/Form/atoms/FormTextArea.tsx b/src/shared/components/molecules/Form/atoms/FormTextArea.tsx
new file mode 100644
index 0000000000..2d7c9588a1
--- /dev/null
+++ b/src/shared/components/molecules/Form/atoms/FormTextArea.tsx
@@ -0,0 +1,123 @@
+import React, {
+ ChangeEventHandler,
+ MouseEventHandler,
+ FocusEventHandler,
+} from 'react'
+import cc from 'classcat'
+import styled from '../../../../lib/styled'
+
+export interface FormTextareaProps {
+ type?: 'text' | 'number' | 'email' | 'password'
+ id?: string
+ className?: string
+ disabled?: boolean
+ placeholder?: string
+ title?: string
+ value?: string
+ defaultValue?: string
+ readOnly?: boolean
+ autoComplete?: 'on' | 'off'
+ onBlur?: FocusEventHandler
+ onChange?: ChangeEventHandler
+ onClick?: MouseEventHandler
+ onMouseUp?: MouseEventHandler
+ onMouseDown?: MouseEventHandler
+ onMouseMove?: MouseEventHandler
+ onMouseOver?: MouseEventHandler
+ onMouseOut?: MouseEventHandler
+ onMouseEnter?: MouseEventHandler
+ onMouseLeave?: MouseEventHandler
+ onDoubleClick?: MouseEventHandler
+ onContextMenu?: MouseEventHandler
+ onFocus?: FocusEventHandler
+}
+
+const FormTextarea = React.forwardRef(
+ (
+ {
+ value,
+ className,
+ type = 'text',
+ autoComplete = 'off',
+ id,
+ placeholder,
+ title,
+ defaultValue,
+ readOnly,
+ disabled,
+ onBlur,
+ onChange,
+ onClick,
+ onMouseUp,
+ onMouseDown,
+ onMouseMove,
+ onMouseOver,
+ onMouseOut,
+ onMouseEnter,
+ onMouseLeave,
+ onDoubleClick,
+ onContextMenu,
+ onFocus,
+ },
+ ref
+ ) => {
+ return (
+
+ )
+ }
+)
+
+export default FormTextarea
+
+const StyledTextarea = styled.textarea`
+ padding: 0 ${({ theme }) => theme.sizes.spaces.sm}px;
+ border-radius: ${({ theme }) => theme.borders.radius}px;
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+ outline: none;
+ background: none;
+ border: 1px solid ${({ theme }) => theme.colors.border.main};
+ color: ${({ theme }) => theme.colors.text.primary};
+ height: 200px;
+ resize: none;
+
+ &:focus {
+ border-color: ${({ theme }) => theme.colors.variants.primary.base};
+ }
+ &::placeholder {
+ color: ${({ theme }) => theme.colors.text.subtle};
+ }
+
+ &:disabled {
+ cursor: not-allowed;
+ opacity: 0.5;
+ }
+
+ &:focus {
+ border-color: ${({ theme }) => theme.colors.variants.info.base};
+ }
+`
diff --git a/src/shared/components/molecules/Form/layouts/FormRow.tsx b/src/shared/components/molecules/Form/layouts/FormRow.tsx
index 4b372d610f..54d5cba702 100644
--- a/src/shared/components/molecules/Form/layouts/FormRow.tsx
+++ b/src/shared/components/molecules/Form/layouts/FormRow.tsx
@@ -11,6 +11,7 @@ import FormSelect, {
} from '../atoms/FormSelect'
import cc from 'classcat'
import FormImage, { FormImageProps } from '../atoms/FormImage'
+import FormTextarea, { FormTextareaProps } from '../atoms/FormTextArea'
export type FormRowButtonProps = ButtonProps & {
label: React.ReactNode
@@ -26,6 +27,10 @@ export type FormRowProps = {
type: 'input'
props: FormInputProps & { ref?: React.Ref }
}
+ | {
+ type: 'textarea'
+ props: FormTextareaProps & { ref?: React.Ref }
+ }
| { type: 'select'; props: FormSelectProps }
| { type: 'select--string'; props: SimpleFormSelectProps }
| { type: 'emoji'; props: FormEmojiProps }
@@ -52,6 +57,8 @@ const FormRow: AppComponent<{ row: FormRowProps }> = ({ row, className }) => {
) : item.type === 'select--string' ? (
+ ) : item.type === 'textarea' ? (
+
) : item.type === 'image' ? (
) : item.type === 'emoji' ? (
diff --git a/src/shared/components/organisms/Modal/index.tsx b/src/shared/components/organisms/Modal/index.tsx
index 2a4640d1fd..d874e280bf 100644
--- a/src/shared/components/organisms/Modal/index.tsx
+++ b/src/shared/components/organisms/Modal/index.tsx
@@ -45,7 +45,6 @@ const ModalItem = ({
const contentRef = useRef(null)
const onScrollClickHandler: React.MouseEventHandler = useCallback(
(event) => {
- console.log('clicked')
if (
contentRef.current != null &&
contentRef.current.contains(event.target as Node)
diff --git a/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx b/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
deleted file mode 100644
index e95ab4d91e..0000000000
--- a/src/shared/components/organisms/Settings/atoms/SettingSelect.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import React from 'react'
-import styled from '../../../../lib/styled'
-
-interface SettingSelectProps {
- label?: string
- value?: string | number
- disabled?: boolean
- onChange?: (val: any) => void
- style?: React.CSSProperties
- options: React.ReactNode
-}
-
-const SettingSelect = ({
- label,
- value,
- disabled,
- onChange,
- options,
-}: SettingSelectProps) => (
-
- {label}
-
- {options}
-
-
-)
-
-const Container = styled.div`
- label {
- display: block;
- margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
- color: ${({ theme }) => theme.colors.text.secondary};
- font-size: ${({ theme }) => theme.sizes.fonts.df}px;
- }
-
- select {
- width: 100%;
- height: 40px;
- min-width: 300px;
- max-width: 450px;
- padding: 0 ${({ theme }) => theme.sizes.spaces.sm}px;
- border-radius: 4px;
- background-color: ${({ theme }) => theme.colors.background.primary};
- border: 1px solid ${({ theme }) => theme.colors.border.main};
- color: ${({ theme }) => theme.colors.text.primary};
-
- &:focus {
- border-color: ${({ theme }) => theme.colors.variants.primary.base};
- }
-
- option {
- color: initial;
- }
- }
-`
-
-export default SettingSelect
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTextarea.tsx b/src/shared/components/organisms/Settings/atoms/SettingTextarea.tsx
deleted file mode 100644
index 51c5c89f5c..0000000000
--- a/src/shared/components/organisms/Settings/atoms/SettingTextarea.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import styled from '../../../../lib/styled'
-
-const SettingTextarea = styled.textarea`
- flex-grow: 1;
- flex-shrink: 1;
- width: 100%;
- height: 200px;
- max-width: 400px;
- padding: ${({ theme }) => theme.sizes.spaces.xsm}px
- ${({ theme }) => theme.sizes.spaces.sm}px;
- background-color: ${({ theme }) => theme.colors.background.primary};
- border: 1px solid ${({ theme }) => theme.colors.border.main};
- border-radius: 4px;
- color: ${({ theme }) => theme.colors.text.primary};
- resize: none;
-
- &:focus {
- border-color: ${({ theme }) => theme.colors.variants.primary.base};
- }
- &::placeholder {
- color: ${({ theme }) => theme.colors.text.subtle};
- }
-`
-
-export default SettingTextarea
From eddb425917b717294362928b677ea021f584a474 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 11:48:15 +0900
Subject: [PATCH 70/91] rename
---
src/cloud/components/organisms/settings/UserPreferencesForm.tsx | 2 +-
src/cloud/lib/hooks/useCloudUI.tsx | 2 +-
src/shared/components/molecules/Form/index.tsx | 2 +-
.../molecules/Form/{layouts => templates}/FormRow.tsx | 0
src/shared/components/organisms/EmojiInputForm.tsx | 2 +-
5 files changed, 4 insertions(+), 4 deletions(-)
rename src/shared/components/molecules/Form/{layouts => templates}/FormRow.tsx (100%)
diff --git a/src/cloud/components/organisms/settings/UserPreferencesForm.tsx b/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
index 1ae521e317..21a34a76c2 100644
--- a/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
+++ b/src/cloud/components/organisms/settings/UserPreferencesForm.tsx
@@ -17,7 +17,7 @@ import FormSelect, {
FormSelectOption,
SimpleFormSelect,
} from '../../../../shared/components/molecules/Form/atoms/FormSelect'
-import FormRow from '../../../../shared/components/molecules/Form/layouts/FormRow'
+import FormRow from '../../../../shared/components/molecules/Form/templates/FormRow'
const UserPreferencesForm = () => {
const { settings, setSettings } = useSettings()
diff --git a/src/cloud/lib/hooks/useCloudUI.tsx b/src/cloud/lib/hooks/useCloudUI.tsx
index b53b03b4ea..e5b003692b 100644
--- a/src/cloud/lib/hooks/useCloudUI.tsx
+++ b/src/cloud/lib/hooks/useCloudUI.tsx
@@ -1,6 +1,6 @@
import { mdiFileDocumentOutline, mdiFolderOutline } from '@mdi/js'
import React, { useCallback } from 'react'
-import { FormRowProps } from '../../../shared/components/molecules/Form/layouts/FormRow'
+import { FormRowProps } from '../../../shared/components/molecules/Form/templates/FormRow'
import EmojiInputForm from '../../../shared/components/organisms/EmojiInputForm'
import { DialogIconTypes, useDialog } from '../../../shared/lib/stores/dialog'
import { useModal } from '../../../shared/lib/stores/modal'
diff --git a/src/shared/components/molecules/Form/index.tsx b/src/shared/components/molecules/Form/index.tsx
index ed5efd8c41..f6dcd32415 100644
--- a/src/shared/components/molecules/Form/index.tsx
+++ b/src/shared/components/molecules/Form/index.tsx
@@ -3,7 +3,7 @@ import styled from '../../../lib/styled'
import { LoadingButton } from '../../atoms/Button'
import cc from 'classcat'
import { AppComponent } from '../../../lib/types'
-import FormRow, { FormRowProps, FormRowButtonProps } from './layouts/FormRow'
+import FormRow, { FormRowProps, FormRowButtonProps } from './templates/FormRow'
interface FormProps {
rows: FormRowProps[]
diff --git a/src/shared/components/molecules/Form/layouts/FormRow.tsx b/src/shared/components/molecules/Form/templates/FormRow.tsx
similarity index 100%
rename from src/shared/components/molecules/Form/layouts/FormRow.tsx
rename to src/shared/components/molecules/Form/templates/FormRow.tsx
diff --git a/src/shared/components/organisms/EmojiInputForm.tsx b/src/shared/components/organisms/EmojiInputForm.tsx
index f28ddf49e0..b1921008f4 100644
--- a/src/shared/components/organisms/EmojiInputForm.tsx
+++ b/src/shared/components/organisms/EmojiInputForm.tsx
@@ -2,7 +2,7 @@ import React, { useRef, useState } from 'react'
import { useEffectOnce } from 'react-use'
import { ButtonProps } from '../atoms/Button'
import Form from '../molecules/Form'
-import { FormRowProps } from '../molecules/Form/layouts/FormRow'
+import { FormRowProps } from '../molecules/Form/templates/FormRow'
interface EmojiInputFormProps {
prevRows?: FormRowProps[]
From a554f4c40335c6039c457a7cd7c8ab2361fabc3a Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 12:07:45 +0900
Subject: [PATCH 71/91] settings token
---
src/cloud/components/Application.tsx | 2 +-
.../components/organisms/settings/ApiTab.tsx | 48 +++++++++++++++++-
.../molecules/Form/templates/FormRow.tsx | 20 +++++++-
.../Settings/molecules/SettingTokenCreate.tsx | 50 -------------------
4 files changed, 66 insertions(+), 54 deletions(-)
delete mode 100644 src/shared/components/organisms/Settings/molecules/SettingTokenCreate.tsx
diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx
index a72680d6dd..507d16caad 100644
--- a/src/cloud/components/Application.tsx
+++ b/src/cloud/components/Application.tsx
@@ -220,7 +220,7 @@ const Application = ({
openSettingsTab('teamUpgrade')
}
- openSettingsTab('personalInfo')
+ openSettingsTab('api')
})
useEffect(() => {
diff --git a/src/cloud/components/organisms/settings/ApiTab.tsx b/src/cloud/components/organisms/settings/ApiTab.tsx
index 08b36da073..20a8023a2e 100644
--- a/src/cloud/components/organisms/settings/ApiTab.tsx
+++ b/src/cloud/components/organisms/settings/ApiTab.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo, useState } from 'react'
+import React, { ChangeEvent, useCallback, useMemo, useState } from 'react'
import styled from '../../../lib/styled'
import Spinner from '../../atoms/CustomSpinner'
import { useApiTokens, withApiTokens } from '../../../lib/stores/apiTokens'
@@ -8,9 +8,9 @@ import Icon from '../../atoms/IconMdi'
import { mdiOpenInNew } from '@mdi/js'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
import Button from '../../../../shared/components/atoms/Button'
-import SettingTokenCreate from '../../../../shared/components/organisms/Settings/molecules/SettingTokenCreate'
import Flexbox from '../../../../shared/components/atoms/Flexbox'
import { ExternalLink } from '../../../../shared/components/atoms/Link'
+import Form from '../../../../shared/components/molecules/Form'
const ApiTab = () => {
const { team } = usePage()
@@ -98,6 +98,46 @@ const ApiTab = () => {
)
}
+const SettingTokenCreate = ({
+ onCreate,
+}: {
+ onCreate: (val: string) => void
+}) => {
+ const [name, setName] = useState('')
+
+ const create = useCallback(() => {
+ onCreate(name)
+ }, [name, onCreate])
+
+ return (
+
+
Create a new token
+
+ )
+}
+
const StyledServiceList = styled.ul`
background-color: ${({ theme }) => theme.baseBackgroundColor};
padding-left: 0;
@@ -111,6 +151,10 @@ const StyledServiceListItem = styled.li`
justify-content: space-between;
padding: ${({ theme }) => theme.space.small}px;
+ .setting__token__form {
+ width: 100%;
+ }
+
+ li {
border-top: 1px solid ${({ theme }) => theme.baseBorderColor};
}
diff --git a/src/shared/components/molecules/Form/templates/FormRow.tsx b/src/shared/components/molecules/Form/templates/FormRow.tsx
index 54d5cba702..3e983bcd32 100644
--- a/src/shared/components/molecules/Form/templates/FormRow.tsx
+++ b/src/shared/components/molecules/Form/templates/FormRow.tsx
@@ -21,6 +21,7 @@ export type FormRowButtonProps = ButtonProps & {
export type FormRowProps = {
layout?: 'column' | 'split'
title?: React.ReactNode
+ required?: boolean
description?: React.ReactNode
items?: (
| {
@@ -42,7 +43,13 @@ export type FormRowProps = {
const FormRow: AppComponent<{ row: FormRowProps }> = ({ row, className }) => {
return (
-
+
{row.title != null && {row.title}
}
{row.items != null && (
@@ -86,7 +93,18 @@ const Container = styled.div`
color: ${({ theme }) => theme.colors.text.subtle};
}
+ &.form__row--required .form__row__title::after {
+ content: '*';
+ color: ${({ theme }) => theme.colors.variants.danger.base};
+ filter: brightness(160%);
+ position: absolute;
+ right: -5px;
+ top: -3px;
+ }
+
.form__row__title {
+ display: inline-block;
+ position: relative;
filter: brightness(80%);
margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
}
diff --git a/src/shared/components/organisms/Settings/molecules/SettingTokenCreate.tsx b/src/shared/components/organisms/Settings/molecules/SettingTokenCreate.tsx
deleted file mode 100644
index 666b07f918..0000000000
--- a/src/shared/components/organisms/Settings/molecules/SettingTokenCreate.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import React, { useState, useCallback, ChangeEvent } from 'react'
-import styled from '../../../../lib/styled'
-import Button from '../../../atoms/Button'
-import Flexbox from '../../../atoms/Flexbox'
-import SettingInput from '../atoms/SettingInput'
-
-interface SettingTokenCreateProps {
- onCreate: (name: string) => void
-}
-
-const SettingTokenCreate = ({ onCreate }: SettingTokenCreateProps) => {
- const [name, setName] = useState('')
-
- const create = useCallback(() => {
- onCreate(name)
- }, [name, onCreate])
-
- return (
-
- Create a token
-
- ) =>
- setName(e.target.value)
- }
- >
-
-
- {name.length === 0 && Enter a name
}
-
- Create
-
-
-
- )
-}
-
-export default SettingTokenCreate
-
-const Container = styled.div`
- width: 100%;
-
- .text--warning {
- margin-top: 0;
- margin-right: ${({ theme }) => theme.sizes.spaces.df}px;
- color: ${({ theme }) => theme.colors.variants.warning.base};
- }
-`
From 7443aa89690837600ab1a599eae547a4ef1d4426 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 12:25:04 +0900
Subject: [PATCH 72/91] teamsublimit
---
.../organisms/settings/TeamSubLimit.tsx | 76 +++++++++++++++++--
.../Settings/atoms/SettingTeamSubLimit.tsx | 69 -----------------
2 files changed, 71 insertions(+), 74 deletions(-)
delete mode 100644 src/shared/components/organisms/Settings/atoms/SettingTeamSubLimit.tsx
diff --git a/src/cloud/components/organisms/settings/TeamSubLimit.tsx b/src/cloud/components/organisms/settings/TeamSubLimit.tsx
index 7e0a8b288a..8ddaa5b167 100644
--- a/src/cloud/components/organisms/settings/TeamSubLimit.tsx
+++ b/src/cloud/components/organisms/settings/TeamSubLimit.tsx
@@ -2,7 +2,7 @@ import React from 'react'
import cc from 'classcat'
import { usePage } from '../../../lib/stores/pageStore'
import { useSettings } from '../../../lib/stores/settings'
-import SettingTeamSubLimit from '../../../../shared/components/organisms/Settings/atoms/SettingTeamSubLimit'
+import styled from '../../../../shared/lib/styled'
const TeamSubLimit = () => {
const { subscription, team, currentSubInfo } = usePage()
@@ -18,7 +18,7 @@ const TeamSubLimit = () => {
if (currentSubInfo.trialing) {
return (
-
+
{
You can upgrade at anytime during your trial.
-
+
)
}
return (
-
+
{
)}
-
+
)
}
+const Container = styled.nav`
+ width: 100%;
+ margin-top: ${({ theme }) => theme.sizes.spaces.l}px;
+
+ h6 {
+ margin: 0;
+ color: ${({ theme }) => theme.colors.variants.primary.base};
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
+ }
+
+ p {
+ margin: ${({ theme }) => theme.sizes.spaces.sm}px 0;
+ color: ${({ theme }) => theme.colors.text.subtle};
+ font-size: ${({ theme }) => theme.sizes.fonts.sm}px;
+ }
+
+ .upgrade-link {
+ display: block;
+ margin-top: ${({ theme }) => theme.sizes.spaces.sm}px;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px;
+ padding: ${({ theme }) => theme.sizes.spaces.df}px;
+ cursor: pointer;
+ text-decoration: none;
+
+ &:hover,
+ &:focus {
+ background-color: ${({ theme }) => theme.colors.background.tertiary};
+ }
+ }
+
+ .note-limit {
+ font-size: ${({ theme }) => theme.sizes.fonts.sm}px;
+ }
+
+ .progress-sm {
+ display: block;
+ position: relative;
+ width: 100%;
+ height: 3px;
+ background-color: ${({ theme }) => theme.colors.background.quaternary};
+ border-radius: 0.25rem;
+ font-size: 0.75rem;
+ overflow: hidden;
+ text-align: center;
+ }
+
+ .progress-bar {
+ flex-direction: column;
+ justify-content: center;
+ height: 3px;
+ max-width: 100%;
+ background-color: ${({ theme }) => theme.colors.background.primary};
+ text-align: center;
+ white-space: nowrap;
+ transition: width 0.6s ease;
+
+ &.over-limit {
+ background-color: ${({ theme }) => theme.colors.variants.danger.base};
+ }
+ }
+
+ .text-danger {
+ color: ${({ theme }) => theme.colors.variants.danger.base};
+ }
+`
+
export default TeamSubLimit
diff --git a/src/shared/components/organisms/Settings/atoms/SettingTeamSubLimit.tsx b/src/shared/components/organisms/Settings/atoms/SettingTeamSubLimit.tsx
deleted file mode 100644
index 723df18239..0000000000
--- a/src/shared/components/organisms/Settings/atoms/SettingTeamSubLimit.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import styled from '../../../../lib/styled'
-
-const SettingTeamSubLimit = styled.nav`
- width: 100%;
- margin-top: ${({ theme }) => theme.sizes.spaces.l}px;
-
- h6 {
- margin: 0;
- color: ${({ theme }) => theme.colors.variants.primary.base};
- font-size: ${({ theme }) => theme.sizes.fonts.df}px;
- }
-
- p {
- margin: ${({ theme }) => theme.sizes.spaces.sm}px 0;
- color: ${({ theme }) => theme.colors.text.subtle};
- font-size: ${({ theme }) => theme.sizes.fonts.sm}px;
- }
-
- .upgrade-link {
- display: block;
- margin-top: ${({ theme }) => theme.sizes.spaces.sm}px;
- margin-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px;
- padding: ${({ theme }) => theme.sizes.spaces.df}px;
- cursor: pointer;
- text-decoration: none;
-
- &:hover,
- &:focus {
- background-color: ${({ theme }) => theme.colors.background.tertiary};
- }
- }
-
- .note-limit {
- font-size: ${({ theme }) => theme.sizes.fonts.sm}px;
- }
-
- .progress-sm {
- display: block;
- position: relative;
- width: 100%;
- height: 3px;
- background-color: ${({ theme }) => theme.colors.background.quaternary};
- border-radius: 0.25rem;
- font-size: 0.75rem;
- overflow: hidden;
- text-align: center;
- }
-
- .progress-bar {
- flex-direction: column;
- justify-content: center;
- height: 3px;
- max-width: 100%;
- background-color: ${({ theme }) => theme.colors.background.primary};
- text-align: center;
- white-space: nowrap;
- transition: width 0.6s ease;
-
- &.over-limit {
- background-color: ${({ theme }) => theme.colors.variants.danger.base};
- }
- }
-
- .text-danger {
- color: ${({ theme }) => theme.colors.variants.danger.base};
- }
-`
-
-export default SettingTeamSubLimit
From 6624a2d661b58ea61e4f671997bbab4f476103aa Mon Sep 17 00:00:00 2001
From: davy-c
Date: Tue, 18 May 2021 12:29:06 +0900
Subject: [PATCH 73/91] single item
---
src/cloud/components/Application.tsx | 2 +-
.../components/molecules/Form/templates/FormRow.tsx | 11 ++++++++++-
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx
index 507d16caad..d9fd6bedb5 100644
--- a/src/cloud/components/Application.tsx
+++ b/src/cloud/components/Application.tsx
@@ -220,7 +220,7 @@ const Application = ({
openSettingsTab('teamUpgrade')
}
- openSettingsTab('api')
+ openSettingsTab('teamInfo')
})
useEffect(() => {
diff --git a/src/shared/components/molecules/Form/templates/FormRow.tsx b/src/shared/components/molecules/Form/templates/FormRow.tsx
index 3e983bcd32..ca00e6c193 100644
--- a/src/shared/components/molecules/Form/templates/FormRow.tsx
+++ b/src/shared/components/molecules/Form/templates/FormRow.tsx
@@ -52,7 +52,12 @@ const FormRow: AppComponent<{ row: FormRowProps }> = ({ row, className }) => {
>
{row.title != null && {row.title}
}
{row.items != null && (
-
+
{row.items.map((item, k) => (
Date: Tue, 18 May 2021 13:11:04 +0900
Subject: [PATCH 74/91] fix tab contnet
---
.../components/molecules/SettingsTeamForm.tsx | 27 ++-------------
.../organisms/settings/MembersTab.tsx | 23 ++++++++-----
.../organisms/settings/SettingsComponent.tsx | 24 +++++++++-----
.../organisms/settings/TeamInfoTab.tsx | 2 +-
.../Settings/atoms/SettingCloseButton.tsx | 33 -------------------
.../Settings/atoms/SettingSidenav.tsx | 11 -------
.../Settings/atoms/SettingTabContent.tsx | 14 ++++++++
.../components/organisms/Settings/index.tsx | 6 ++++
8 files changed, 54 insertions(+), 86 deletions(-)
delete mode 100644 src/shared/components/organisms/Settings/atoms/SettingCloseButton.tsx
delete mode 100644 src/shared/components/organisms/Settings/atoms/SettingSidenav.tsx
diff --git a/src/cloud/components/molecules/SettingsTeamForm.tsx b/src/cloud/components/molecules/SettingsTeamForm.tsx
index 61a0b61116..2c7ccda7a7 100644
--- a/src/cloud/components/molecules/SettingsTeamForm.tsx
+++ b/src/cloud/components/molecules/SettingsTeamForm.tsx
@@ -1,4 +1,4 @@
-import { mdiArrowLeft, mdiDomain } from '@mdi/js'
+import { mdiDomain } from '@mdi/js'
import React, { useCallback, useMemo, useState } from 'react'
import slugify from 'slugify'
import { buildIconUrl } from '../../api/files'
@@ -21,16 +21,9 @@ import SettingIconInputLabel from '../../../shared/components/organisms/Settings
interface SettingsTeamFormProps {
team: SerializedTeam
teamConversion?: boolean
- header?: boolean
- onCancel?: () => void
}
-const SettingsTeamForm = ({
- team,
- teamConversion,
- header = true,
- onCancel,
-}: SettingsTeamFormProps) => {
+const SettingsTeamForm = ({ team, teamConversion }: SettingsTeamFormProps) => {
const [name, setName] = useState
(!teamConversion ? team.name : '')
const [domain, setDomain] = useState(
!teamConversion ? team.domain : ''
@@ -137,22 +130,6 @@ const SettingsTeamForm = ({
return (
)
diff --git a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx
index 6063847430..9a9c503d1f 100644
--- a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx
@@ -1,14 +1,13 @@
import React, { useState, useCallback } from 'react'
-import {
- SectionIntroduction,
- SectionFlexDualButtons,
-} from '../../organisms/settings/styled'
-import CustomButton from '../../atoms/buttons/CustomButton'
+import { SectionIntroduction } from '../../organisms/settings/styled'
import { SerializedSubscription } from '../../../interfaces/db/subscription'
import { StyledBillingInput } from '.'
-import { Spinner } from '../../atoms/Spinner'
import { redeemPromo } from '../../../api/teams/subscription'
import { useToast } from '../../../../shared/lib/stores/toast'
+import Button, {
+ LoadingButton,
+} from '../../../../shared/components/atoms/Button'
+import ButtonGroup from '../../../../shared/components/atoms/ButtonGroup'
interface UpdateBillingPromoFormProps {
sub?: SerializedSubscription
@@ -68,15 +67,9 @@ const UpdateBillingPromoForm = ({
You need to have a valid subscription to perform this action.
-
-
- Cancel
-
-
+
+ Cancel
+
)
@@ -93,19 +86,20 @@ const UpdateBillingPromoForm = ({
onChange={onPromoInputChangeHandler}
/>
-
-
+
+
Cancel
-
+
-
- {sending ? : 'Apply'}
-
-
+
+ Apply
+
+
)
diff --git a/src/cloud/components/molecules/SubscriptionForm/index.tsx b/src/cloud/components/molecules/SubscriptionForm/index.tsx
index dee0d215cd..edaf8f35d2 100644
--- a/src/cloud/components/molecules/SubscriptionForm/index.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/index.tsx
@@ -3,13 +3,11 @@ import { useStripe, useElements, CardElement } from '@stripe/react-stripe-js'
import { createSubscription } from '../../../api/teams/subscription'
import { SerializedTeam } from '../../../interfaces/db/team'
import { SerializedSubscription } from '../../../interfaces/db/subscription'
-import { SectionFlexDualButtons } from '../../organisms/settings/styled'
import { inputStyle } from '../../../lib/styled/styleFunctions'
import styled from '../../../lib/styled'
import Stripe, { StripeElementStyle } from '@stripe/stripe-js'
import { useSettings } from '../../../lib/stores/settings'
import { selectTheme } from '../../../lib/styled'
-import { Spinner } from '../../atoms/Spinner'
import { usePage } from '../../../lib/stores/pageStore'
import {
stripeProPlanUnit,
@@ -23,7 +21,10 @@ import Icon from '../../../../components/atoms/Icon'
import { mdiChevronDown, mdiChevronRight } from '@mdi/js'
import Alert from '../../../../components/atoms/Alert'
import { useToast } from '../../../../shared/lib/stores/toast'
-import Button from '../../../../shared/components/atoms/Button'
+import Button, {
+ LoadingButton,
+} from '../../../../shared/components/atoms/Button'
+import ButtonGroup from '../../../../shared/components/atoms/ButtonGroup'
interface SubscriptionFormProps {
team: SerializedTeam
@@ -236,9 +237,7 @@ const SubscriptionForm = ({
onChange={onPromoCodeInputChangeHandler}
/>
)}
-
+
{onCancel != null && (
)}
-
- {sending ? : 'Subscribe'}
-
-
+ Subscribe
+
+
)
}
@@ -361,6 +361,10 @@ export const StyledSubscriptionForm = styled.form`
margin-left: ${({ theme }) => theme.space.xxsmall}px;
}
}
+
+ .button__group {
+ margin-top: 40px;
+ }
`
export const StyledCardElementContainer = styled.div`
diff --git a/src/cloud/components/organisms/settings/styled.ts b/src/cloud/components/organisms/settings/styled.ts
index d60d4fbb0c..0269a56cf5 100644
--- a/src/cloud/components/organisms/settings/styled.ts
+++ b/src/cloud/components/organisms/settings/styled.ts
@@ -93,24 +93,3 @@ export const SectionFlexRow = styled.div`
}
}
`
-
-export const SectionFlexDualButtons = styled.div`
- display: flex;
- align-items: center;
- justify-content: flex-end;
-
- &.marginTop {
- margin-top: ${({ theme }) => theme.space.medium}px;
- }
-
- button {
- margin-left: ${({ theme }) => theme.space.small}px;
-
- svg {
- position: relative !important;
- transform: none !important;
- top: initial !important;
- left: initial !important;
- }
- }
-`
diff --git a/src/shared/components/atoms/ButtonGroup.tsx b/src/shared/components/atoms/ButtonGroup.tsx
index 225388caab..36a78e835f 100644
--- a/src/shared/components/atoms/ButtonGroup.tsx
+++ b/src/shared/components/atoms/ButtonGroup.tsx
@@ -1,33 +1,63 @@
import React from 'react'
-import styled from '../../../lib/styled'
+import { AppComponent } from '../../lib/types'
+import cc from 'classcat'
+import styled from '../../lib/styled'
interface ButtonGroupProps {
- children: React.ReactNode
+ display?: 'inline-flex' | 'flex'
+ layout?: 'collapsed' | 'spread'
+ justifyContent?: 'flex-start' | 'flex-end'
}
-const ButtonGroup = ({ children }: ButtonGroupProps) => {
- return
{children}
+const ButtonGroup: AppComponent
= ({
+ children,
+ display = 'inline-flex',
+ layout = 'collapsed',
+ justifyContent = 'flex-start',
+}) => {
+ return (
+
+ {children}
+
+ )
}
-const StyledButtonGroup = styled.div`
- display: inline-flex;
+const StyledButtonGroup = styled.div<{
+ display: string
+ justifyContent: string
+}>`
+ display: ${({ display }) => display};
+ justify-content: ${({ justifyContent }) => justifyContent};
position: relative;
- & > button:first-child {
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- flex: 1 1 auto;
- }
+ &.button__group--spread {
+ align-items: center;
- & > button:last-child {
- border-top-left-radius: 0;
- border-bottom-left-radius: 0;
- margin: 0;
- flex: 0 0 auto;
+ button + button {
+ margin-left: ${({ theme }) => theme.sizes.spaces.sm}px;
+ }
}
- & > button:not(:first-child):not(:last-child) {
- border-radius: 0;
+ &.button__group--collapsed {
+ > button:nth-child(2n + 1) {
+ margin: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+
+ > button:nth-child(2n) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ margin: 0;
+ }
+
+ > button:not(:first-child):not(:last-child) {
+ border-radius: 0;
+ }
}
`
From 00993d779c6ec553104aa03953ef5895ce74fa7c Mon Sep 17 00:00:00 2001
From: davy-c
Date: Wed, 19 May 2021 09:44:50 +0900
Subject: [PATCH 82/91] promises and invalid dom nesting
---
.../molecules/OpenInviteSection.tsx | 33 ++++++---
.../molecules/TeamInvitesSection.tsx | 36 +++++++---
.../organisms/settings/MembersTab.tsx | 71 +++++++++++++------
.../organisms/settings/SubscriptionTab.tsx | 4 +-
.../organisms/settings/UpgradeTab.tsx | 4 +-
5 files changed, 106 insertions(+), 42 deletions(-)
diff --git a/src/cloud/components/molecules/OpenInviteSection.tsx b/src/cloud/components/molecules/OpenInviteSection.tsx
index 249e66b90a..e1c4edde50 100644
--- a/src/cloud/components/molecules/OpenInviteSection.tsx
+++ b/src/cloud/components/molecules/OpenInviteSection.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useCallback, useMemo } from 'react'
+import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react'
import { SectionRow } from '../organisms/settings/styled'
import { useDialog, DialogIconTypes } from '../../../shared/lib/stores/dialog'
import { usePage } from '../../lib/stores/pageStore'
@@ -33,6 +33,14 @@ const OpenInvitesSection = ({ userPermissions }: OpenInvitesSectionProps) => {
>(undefined)
const { messageBox } = useDialog()
const { pushApiErrorMessage } = useToast()
+ const mountedRef = useRef(false)
+
+ useEffect(() => {
+ mountedRef.current = true
+ return () => {
+ mountedRef.current = false
+ }
+ }, [])
useEffectOnce(() => {
fetchOpenInvite()
@@ -43,13 +51,22 @@ const OpenInvitesSection = ({ userPermissions }: OpenInvitesSectionProps) => {
return
}
setFetching(true)
- try {
- const { invite } = await getOpenInvite(team)
- setOpenInvite(invite)
- setFetching(false)
- } catch (error) {
- pushApiErrorMessage(error)
- }
+ getOpenInvite(team)
+ .then(({ invite }) => {
+ if (!mountedRef.current) {
+ return
+ }
+ setOpenInvite(invite)
+ })
+ .catch((error) => {
+ pushApiErrorMessage(error)
+ })
+ .then(() => {
+ if (!mountedRef.current) {
+ return
+ }
+ setFetching(false)
+ })
}, [team, pushApiErrorMessage])
const createInvite = useCallback(async () => {
diff --git a/src/cloud/components/molecules/TeamInvitesSection.tsx b/src/cloud/components/molecules/TeamInvitesSection.tsx
index 2c4dd2a993..7acf107bd0 100644
--- a/src/cloud/components/molecules/TeamInvitesSection.tsx
+++ b/src/cloud/components/molecules/TeamInvitesSection.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useCallback } from 'react'
+import React, { useState, useCallback, useRef, useEffect } from 'react'
import {
SectionList,
SectionListItem,
@@ -36,6 +36,14 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
const [error, setError] = useState()
const { messageBox } = useDialog()
const [role, setRole] = useState('member')
+ const mountedRef = useRef(false)
+
+ useEffect(() => {
+ mountedRef.current = true
+ return () => {
+ mountedRef.current = false
+ }
+ }, [])
useEffectOnce(() => {
fetchAndSetInvites()
@@ -46,13 +54,25 @@ const TeamInvitesSection = ({ userPermissions }: TeamInvitesSectionProps) => {
return
}
setSending(true)
- try {
- const { invites } = await getTeamInvites(team)
- setPendingInvites(invites)
- } catch (error) {
- setError(error)
- }
- setSending(false)
+ getTeamInvites(team)
+ .then(({ invites }) => {
+ if (!mountedRef.current) {
+ return
+ }
+ setPendingInvites(invites)
+ })
+ .catch((error) => {
+ if (!mountedRef.current) {
+ return
+ }
+ setError(error)
+ })
+ .finally(() => {
+ if (!mountedRef.current) {
+ return
+ }
+ setSending(false)
+ })
}, [team])
const onChangeHandler = useCallback(
diff --git a/src/cloud/components/organisms/settings/MembersTab.tsx b/src/cloud/components/organisms/settings/MembersTab.tsx
index 1d8928e35f..d74aa2578e 100644
--- a/src/cloud/components/organisms/settings/MembersTab.tsx
+++ b/src/cloud/components/organisms/settings/MembersTab.tsx
@@ -86,21 +86,40 @@ const MembersTab = () => {
const [showTeamPersonalForm, setShowTeamPersonalForm] = useState(
false
)
+ const mountedRef = useRef(false)
+
+ useEffect(() => {
+ mountedRef.current = true
+ return () => {
+ mountedRef.current = false
+ }
+ }, [])
const fetchUserEmails = useCallback(
async (teamId: string, ids: string[]) => {
add('userEmails')
- try {
- const res = await getUserEmailsFromPermissions(teamId, ids)
- setUserEmailsMap(() =>
- res.permissionEmails.reduce((acc, val) => {
- acc.set(val.id, val.email)
- return acc
- }, new Map())
- )
- } catch (error) {}
- currentUserEmailIds.current = ids
- remove('userEmails')
+ getUserEmailsFromPermissions(teamId, ids)
+ .then((res) => {
+ if (!mountedRef.current) {
+ return
+ }
+ setUserEmailsMap(() =>
+ res.permissionEmails.reduce((acc, val) => {
+ acc.set(val.id, val.email)
+ return acc
+ }, new Map())
+ )
+ })
+ .catch(() => {
+ //
+ })
+ .finally(() => {
+ if (!mountedRef.current) {
+ return
+ }
+ currentUserEmailIds.current = ids
+ remove('userEmails')
+ })
},
[add, remove]
)
@@ -108,17 +127,25 @@ const MembersTab = () => {
const fetchGuestsEmails = useCallback(
async (teamId: string, ids: string[]) => {
add('guestEmails')
- try {
- const res = await getGuestsEmails({ teamId })
- setGuestEmailsMap(() =>
- res.guestsEmails.reduce((acc, val) => {
- acc.set(val.id, val.email)
- return acc
- }, new Map())
- )
- } catch (error) {}
- currentGuestsEmailIds.current = ids
- remove('guestEmails')
+ getGuestsEmails({ teamId })
+ .then((res) => {
+ if (!mountedRef.current) {
+ return
+ }
+ setGuestEmailsMap(() =>
+ res.guestsEmails.reduce((acc, val) => {
+ acc.set(val.id, val.email)
+ return acc
+ }, new Map())
+ )
+ })
+ .catch(() => {
+ //
+ })
+ .finally(() => {
+ currentGuestsEmailIds.current = ids
+ remove('guestEmails')
+ })
},
[add, remove]
)
diff --git a/src/cloud/components/organisms/settings/SubscriptionTab.tsx b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
index b431ffa3fd..c3d321dc29 100644
--- a/src/cloud/components/organisms/settings/SubscriptionTab.tsx
+++ b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
@@ -81,7 +81,7 @@ const SubscriptionTab = () => {
title={t('settings.teamSubscription')}
body={
-
+
{formtab == null ? (
{
) : null}
)}
-
+
}
>
diff --git a/src/cloud/components/organisms/settings/UpgradeTab.tsx b/src/cloud/components/organisms/settings/UpgradeTab.tsx
index 2e4d5484b9..a9e5098ef1 100644
--- a/src/cloud/components/organisms/settings/UpgradeTab.tsx
+++ b/src/cloud/components/organisms/settings/UpgradeTab.tsx
@@ -115,7 +115,7 @@ const UpgradeTab = () => {
title={t('settings.teamUpgrade')}
body={
-
+
{currentUserPermissions.role !== 'admin' ? (
Only admins can access this content.
@@ -138,7 +138,7 @@ const UpgradeTab = () => {
)
)}
-
+
}
>
From cf5efd147a56f9795d10b267bf27efd9db559247 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Wed, 19 May 2021 10:43:35 +0900
Subject: [PATCH 83/91] rename and fix ordering sidebar bookmarks
---
src/cloud/components/Application.tsx | 865 +-----------------
.../components/molecules/Editor/index.tsx | 8 +-
.../components/molecules/NewDocButton.tsx | 4 +-
.../components/organisms/DocPage/View.tsx | 8 +-
.../components/organisms/FolderPage/index.tsx | 8 +-
.../SideNavigatorFolderControls.tsx | 4 +-
.../SideNavigatorWorkspaceControls.tsx | 4 +-
.../ControlsContextMenu/FolderContextMenu.tsx | 4 +-
.../organisms/WorkspacePage/index.tsx | 4 +-
.../useCloudSidebarDnd.ts} | 26 +-
.../lib/hooks/sidebar/useCloudSidebarTree.tsx | 802 ++++++++++++++++
.../{useCloudUpdater.ts => useCloudApi.ts} | 2 +-
...CloudUI.tsx => useCloudResourceModals.tsx} | 6 +-
src/cloud/lib/mappers/topbarBreadcrumbs.ts | 5 +-
14 files changed, 853 insertions(+), 897 deletions(-)
rename src/cloud/lib/hooks/{useCloudDnd.ts => sidebar/useCloudSidebarDnd.ts} (82%)
create mode 100644 src/cloud/lib/hooks/sidebar/useCloudSidebarTree.tsx
rename src/cloud/lib/hooks/{useCloudUpdater.ts => useCloudApi.ts} (99%)
rename src/cloud/lib/hooks/{useCloudUI.tsx => useCloudResourceModals.tsx} (98%)
diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx
index 78bb45ea02..c45465e71e 100644
--- a/src/cloud/components/Application.tsx
+++ b/src/cloud/components/Application.tsx
@@ -26,27 +26,16 @@ import { useNav } from '../lib/stores/nav'
import EventSource from './organisms/EventSource'
import ApplicationLayout from '../../shared/components/molecules/ApplicationLayout'
import Sidebar from '../../shared/components/organisms/Sidebar'
-import {
- CollapsableType,
- useSidebarCollapse,
-} from '../lib/stores/sidebarCollapse'
-import {
- MenuItem,
- MenuTypes,
- useContextMenu,
-} from '../../shared/lib/stores/contextMenu'
+import { MenuTypes, useContextMenu } from '../../shared/lib/stores/contextMenu'
import { useGlobalData } from '../lib/stores/globalData'
import { getDocLinkHref } from './atoms/Link/DocLink'
import { getFolderHref } from './atoms/Link/FolderLink'
-import { getWorkspaceHref } from './atoms/Link/WorkspaceLink'
-import { getTagHref } from './atoms/Link/TagLink'
import {
SidebarSearchHistory,
SidebarSearchResult,
} from '../../shared/components/organisms/Sidebar/molecules/SidebarSearch'
import {
SidebarState,
- SidebarTreeSortingOrder,
SidebarTreeSortingOrders,
} from '../../shared/lib/sidebar'
import useApi from '../../shared/lib/hooks/useApi'
@@ -58,58 +47,24 @@ import {
} from '../api/search'
import { SidebarToolbarRow } from '../../shared/components/organisms/Sidebar/molecules/SidebarToolbar'
import { mapUsers } from '../../shared/lib/mappers/users'
-import { SerializedDoc, SerializedDocWithBookmark } from '../interfaces/db/doc'
+import { SerializedDoc } from '../interfaces/db/doc'
import { SerializedTeam } from '../interfaces/db/team'
import { compareDateString } from '../../shared/lib/date'
-import {
- getDocId,
- getDocTitle,
- getFolderId,
- getTeamURL,
-} from '../lib/utils/patterns'
+import { getDocTitle, getTeamURL } from '../lib/utils/patterns'
import {
mdiAccountMultiplePlusOutline,
- mdiApplicationCog,
- mdiArchiveOutline,
mdiClockOutline,
mdiCogOutline,
mdiDownload,
mdiFileDocumentMultipleOutline,
mdiFileDocumentOutline,
- mdiFilePlusOutline,
- mdiFolderPlusOutline,
- mdiLock,
mdiLogoutVariant,
mdiMagnify,
- mdiPaperclip,
- mdiPencil,
- mdiPlus,
mdiPlusCircleOutline,
- mdiStar,
- mdiStarOutline,
- mdiTag,
- mdiTrashCanOutline,
- mdiWeb,
} from '@mdi/js'
import { getColorFromString } from '../../shared/lib/string'
-import {
- sortByAttributeAsc,
- sortByAttributeDesc,
-} from '../../shared/lib/utils/array'
import { buildIconUrl } from '../api/files'
-import {
- SerializedFolder,
- SerializedFolderWithBookmark,
-} from '../interfaces/db/folder'
-import { SerializedWorkspace } from '../interfaces/db/workspace'
-import { SerializedTag } from '../interfaces/db/tag'
-import { FoldingProps } from '../../shared/components/atoms/FoldingWrapper'
-import { getMapValues } from '../../shared/lib/utils/array'
-import {
- SidebarNavCategory,
- SidebarNavControls,
- SidebarTreeChildRow,
-} from '../../shared/components/organisms/Sidebar/molecules/SidebarTree'
+import { SerializedFolder } from '../interfaces/db/folder'
import RoundedImage from '../../shared/components/atoms/RoundedImage'
import ImportModal from './organisms/Modal/contents/Import/ImportModal'
import { SerializedTeamInvite } from '../interfaces/db/teamInvite'
@@ -121,15 +76,8 @@ import ContentLayout, {
ContentLayoutProps,
} from '../../shared/components/templates/ContentLayout'
import { getTeamLinkHref } from './atoms/Link/TeamLink'
-import CreateWorkspaceModal from './organisms/Modal/contents/Workspace/CreateWorkspaceModal'
-import { useCloudUpdater } from '../lib/hooks/useCloudUpdater'
-import { CreateFolderRequestBody } from '../api/teams/folders'
-import { CreateDocRequestBody } from '../api/teams/docs'
-import { useCloudDnd } from '../lib/hooks/useCloudDnd'
-import { NavResource } from '../interfaces/resources'
-import { SidebarDragState } from '../../shared/lib/dnd'
import cc from 'classcat'
-import { useCloudUI } from '../lib/hooks/useCloudUI'
+import { useCloudResourceModals } from '../lib/hooks/useCloudResourceModals'
import { mapTopbarTree } from '../lib/mappers/topbarTree'
import FuzzyNavigation from '../../shared/components/organisms/FuzzyNavigation'
import {
@@ -137,12 +85,8 @@ import {
mapFuzzyNavigationRecentItems,
} from '../lib/mappers/fuzzyNavigation'
import { ModalOpeningOptions, useModal } from '../../shared/lib/stores/modal'
-import { CreateWorkspaceRequestBody } from '../api/teams/workspaces'
-import {
- cloudSidebaCategoryLabels,
- cloudSidebarOrderedCategoriesDelimiter,
-} from '../lib/sidebar'
import NewDocButton from './molecules/NewDocButton'
+import { useCloudSidebarTree } from '../lib/hooks/sidebar/useCloudSidebarTree'
interface ApplicationProps {
content: ContentLayoutProps
@@ -161,18 +105,9 @@ const Application = ({
docsMap,
foldersMap,
workspacesMap,
- tagsMap,
currentParentFolderId,
currentWorkspaceId,
} = useNav()
- const {
- sideBarOpenedLinksIdsSet,
- sideBarOpenedFolderIdsSet,
- sideBarOpenedWorkspaceIdsSet,
- toggleItem,
- unfoldItem,
- foldItem,
- } = useSidebarCollapse()
const {
team,
permissions = [],
@@ -195,14 +130,10 @@ const Application = ({
)
const { openSettingsTab, closeSettingsTab } = useSettings()
const { usingElectron, sendToElectron } = useElectron()
- const {
- openRenameFolderForm,
- openNewFolderForm,
- openRenameDocForm,
- openWorkspaceEditForm,
- } = useCloudUI()
+ const { openNewFolderForm } = useCloudResourceModals()
const [showFuzzyNavigation, setShowFuzzyNavigation] = useState(false)
const { popup } = useContextMenu()
+ const { treeWithOrderedCategories } = useCloudSidebarTree()
usePathnameChangeEffect(() => {
setShowFuzzyNavigation(false)
@@ -232,193 +163,11 @@ const Application = ({
setSidebarState((prev) => (prev === state ? undefined : state))
}, [])
- const getFoldEvents = useCallback(
- (type: CollapsableType, key: string, reversed?: boolean) => {
- if (reversed) {
- return {
- fold: () => unfoldItem(type, key),
- unfold: () => foldItem(type, key),
- toggle: () => toggleItem(type, key),
- }
- }
-
- return {
- fold: () => foldItem(type, key),
- unfold: () => unfoldItem(type, key),
- toggle: () => toggleItem(type, key),
- }
- },
- [toggleItem, unfoldItem, foldItem]
- )
-
const sidebarResize = useCallback(
(width: number) => setPreferences({ sideBarWidth: width }),
[setPreferences]
)
- const {
- draggedCategory,
- draggedResource,
- dropInDocOrFolder,
- dropInWorkspace,
- } = useCloudDnd()
- const {
- sendingMap: treeSendingMap,
- createWorkspace,
- createDoc,
- createFolder,
- toggleDocArchive,
- toggleDocBookmark,
- toggleFolderBookmark,
- updateDoc,
- updateFolder,
- } = useCloudUpdater()
- const { deleteWorkspace, deleteFolder } = useCloudUI()
-
- const tree = useMemo(() => {
- return mapTree(
- initialLoadDone,
- preferences.sidebarTreeSortingOrder,
- pathname,
- docsMap,
- foldersMap,
- workspacesMap,
- tagsMap,
- treeSendingMap,
- sideBarOpenedLinksIdsSet,
- sideBarOpenedFolderIdsSet,
- sideBarOpenedWorkspaceIdsSet,
- toggleItem,
- getFoldEvents,
- push,
- openModal,
- toggleDocBookmark,
- toggleFolderBookmark,
- createWorkspace,
- deleteWorkspace,
- toggleDocArchive,
- deleteFolder,
- createFolder,
- createDoc,
- draggedResource,
- dropInDocOrFolder,
- (id: string) => dropInWorkspace(id, updateFolder, updateDoc),
- openRenameFolderForm,
- openRenameDocForm,
- openWorkspaceEditForm,
- team
- )
- }, [
- initialLoadDone,
- preferences.sidebarTreeSortingOrder,
- pathname,
- docsMap,
- foldersMap,
- workspacesMap,
- tagsMap,
- treeSendingMap,
- sideBarOpenedFolderIdsSet,
- sideBarOpenedLinksIdsSet,
- sideBarOpenedWorkspaceIdsSet,
- toggleItem,
- getFoldEvents,
- push,
- openModal,
- toggleDocBookmark,
- toggleFolderBookmark,
- createWorkspace,
- deleteWorkspace,
- toggleDocArchive,
- deleteFolder,
- createFolder,
- createDoc,
- dropInDocOrFolder,
- dropInWorkspace,
- updateFolder,
- updateDoc,
- openRenameFolderForm,
- openRenameDocForm,
- openWorkspaceEditForm,
- draggedResource,
- team,
- ])
-
- const treeWithOrderedCategories = useMemo(() => {
- if (tree == null) {
- return undefined
- }
-
- const orderedCategories = Array.from(
- new Set([
- ...preferences.sidebarOrderedCategories.split(
- cloudSidebarOrderedCategoriesDelimiter
- ),
- ...cloudSidebaCategoryLabels,
- ])
- ).filter((item) =>
- cloudSidebaCategoryLabels.find((categoryLabel) => categoryLabel === item)
- )
-
- const orderedTree = tree.sort((categoryA, categoryB) => {
- if (
- orderedCategories.indexOf(categoryA.label) >
- orderedCategories.indexOf(categoryB.label)
- ) {
- return 1
- } else {
- return -1
- }
- })
-
- orderedTree.forEach((category) => {
- category.drag = {
- onDragStart: () => {
- draggedCategory.current = category.label
- },
- onDragEnd: () => {
- draggedCategory.current = undefined
- },
- onDrop: () => {
- if (draggedCategory.current == null) {
- return
- }
- const orderedItems = orderedCategories.splice(0)
- const categoryIndex = orderedItems.includes(category.label)
- ? orderedItems.indexOf(category.label)
- : orderedItems.length - 1
-
- const reArrangedArray = orderedItems.reduce((acc, val, i) => {
- if (i === categoryIndex) {
- acc.push(draggedCategory.current!)
- }
-
- if (i !== categoryIndex && val === draggedCategory.current) {
- return acc
- }
-
- acc.push(val)
- return acc
- }, [] as string[])
-
- setPreferences({
- sidebarOrderedCategories: reArrangedArray.join(
- cloudSidebarOrderedCategoriesDelimiter
- ),
- })
-
- draggedCategory.current = undefined
- },
- }
- })
-
- return orderedTree
- }, [
- tree,
- preferences.sidebarOrderedCategories,
- setPreferences,
- draggedCategory,
- ])
-
const users = useMemo(() => {
return mapUsers(permissions, currentUser, [...guestsMap.values()])
}, [permissions, currentUser, guestsMap])
@@ -861,537 +610,6 @@ function mapHistory(
return items
}
-function mapTree(
- initialLoadDone: boolean,
- sortingOrder: SidebarTreeSortingOrder,
- currentPath: string,
- docsMap: Map,
- foldersMap: Map,
- workspacesMap: Map,
- tagsMap: Map,
- treeSendingMap: Map,
- sideBarOpenedLinksIdsSet: Set,
- sideBarOpenedFolderIdsSet: Set,
- sideBarOpenedWorkspaceIdsSet: Set,
- toggleItem: (type: CollapsableType, id: string) => void,
- getFoldEvents: (
- type: CollapsableType,
- key: string,
- reversed?: boolean
- ) => FoldingProps,
- push: (url: string) => void,
- openModal: (cmp: JSX.Element) => void,
- toggleDocBookmark: (
- teamId: string,
- docId: string,
- bookmarked: boolean
- ) => void,
- toggleFolderBookmark: (
- teamId: string,
- id: string,
- bookmarked: boolean
- ) => void,
- createWorkspace: (
- team: SerializedTeam,
- body: CreateWorkspaceRequestBody,
- options: {
- skipRedirect?: boolean
- afterSuccess?: (workspace: SerializedWorkspace) => void
- }
- ) => void,
- deleteWorkspace: (wp: SerializedWorkspace) => void,
- toggleDocArchive: (
- teamId: string,
- docId: string,
- archivedAt?: string
- ) => void,
- deleteFolder: (folder: SerializedFolder) => void,
- createFolder: (
- team: SerializedTeam,
- body: CreateFolderRequestBody
- ) => Promise,
- createDoc: (
- team: SerializedTeam,
- body: CreateDocRequestBody
- ) => Promise,
- draggedResource: React.MutableRefObject,
- dropInFolderOrDoc: (
- targetedResource: NavResource,
- targetedPosition: SidebarDragState
- ) => void,
- dropInWorkspace: (id: string) => void,
- openRenameFolderForm: (folder: SerializedFolder) => void,
- openRenameDocForm: (doc: SerializedDoc) => void,
- openWorkspaceEditForm: (wp: SerializedWorkspace) => void,
- team?: SerializedTeam
-) {
- if (!initialLoadDone || team == null) {
- return undefined
- }
-
- const currentPathWithDomain = `${process.env.BOOST_HUB_BASE_URL}${currentPath}`
- const items = new Map()
-
- const [docs, folders, workspaces] = [
- getMapValues(docsMap),
- getMapValues(foldersMap),
- getMapValues(workspacesMap),
- ]
-
- let personalWorkspace: SerializedWorkspace | undefined
- workspaces.forEach((wp) => {
- if (wp.personal) {
- personalWorkspace = wp
- return
- }
-
- const href = `${process.env.BOOST_HUB_BASE_URL}${getWorkspaceHref(
- wp,
- team,
- 'index'
- )}`
- items.set(wp.id, {
- id: wp.id,
- lastUpdated: wp.updatedAt,
- label: wp.name,
- defaultIcon: !wp.public ? mdiLock : undefined,
- children: wp.positions?.orderedIds || [],
- folded: !sideBarOpenedWorkspaceIdsSet.has(wp.id),
- folding: getFoldEvents('workspaces', wp.id),
- href,
- active: href === currentPathWithDomain,
- navigateTo: () => push(href),
- dropIn: true,
- onDrop: () => dropInWorkspace(wp.id),
- controls: [
- {
- icon: mdiFilePlusOutline,
- onClick: undefined,
- placeholder: 'Doc title..',
- create: (title: string) =>
- createDoc(team, {
- workspaceId: wp.id,
- title,
- }),
- },
- {
- icon: mdiFolderPlusOutline,
- onClick: undefined,
- placeholder: 'Folder name..',
- create: (folderName: string) =>
- createFolder(team, {
- workspaceId: wp.id,
- description: '',
- folderName,
- }),
- },
- ],
- contextControls: wp.default
- ? [
- {
- type: MenuTypes.Normal,
- icon: mdiApplicationCog,
- label: 'Edit',
- onClick: () => openWorkspaceEditForm(wp),
- },
- ]
- : [
- {
- type: MenuTypes.Normal,
- icon: mdiApplicationCog,
- label: 'Edit',
- onClick: () => openWorkspaceEditForm(wp),
- },
- {
- type: MenuTypes.Normal,
- icon: mdiTrashCanOutline,
- label: 'Delete',
- onClick: () => deleteWorkspace(wp),
- },
- ],
- })
- })
-
- folders.forEach((folder) => {
- const folderId = getFolderId(folder)
- const href = `${process.env.BOOST_HUB_BASE_URL}${getFolderHref(
- folder,
- team,
- 'index'
- )}`
- items.set(folderId, {
- id: folderId,
- lastUpdated: folder.updatedAt,
- label: folder.name,
- bookmarked: folder.bookmarked,
- emoji: folder.emoji,
- folded: !sideBarOpenedFolderIdsSet.has(folder.id),
- folding: getFoldEvents('folders', folder.id),
- href,
- active: href === currentPathWithDomain,
- navigateTo: () => push(href),
- onDrop: (position: SidebarDragState) =>
- dropInFolderOrDoc({ type: 'folder', result: folder }, position),
- onDragStart: () => {
- draggedResource.current = { type: 'folder', result: folder }
- },
- onDragEnd: () => {
- draggedResource.current = undefined
- },
- dropIn: true,
- dropAround: sortingOrder === 'drag' ? true : false,
- controls: [
- {
- icon: mdiFilePlusOutline,
- onClick: undefined,
- placeholder: 'Doc title..',
- create: (title: string) =>
- createDoc(team, {
- parentFolderId: folder.id,
- workspaceId: folder.workspaceId,
- title,
- }),
- },
- {
- icon: mdiFolderPlusOutline,
- onClick: undefined,
- placeholder: 'Folder name..',
- create: (folderName: string) =>
- createFolder(team, {
- parentFolderId: folder.id,
- workspaceId: folder.workspaceId,
- description: '',
- folderName,
- }),
- },
- ],
- contextControls: [
- {
- type: MenuTypes.Normal,
- icon: folder.bookmarked ? mdiStar : mdiStarOutline,
- label:
- treeSendingMap.get(folder.id) === 'bookmark'
- ? '...'
- : folder.bookmarked
- ? 'Bookmarked'
- : 'Bookmark',
- onClick: () =>
- toggleFolderBookmark(folder.teamId, folder.id, folder.bookmarked),
- },
- {
- type: MenuTypes.Normal,
- icon: mdiPencil,
- label: 'Rename',
- onClick: () => openRenameFolderForm(folder),
- },
- {
- type: MenuTypes.Normal,
- icon: mdiTrashCanOutline,
- label: 'Delete',
- onClick: () => deleteFolder(folder),
- },
- ],
- parentId:
- folder.parentFolderId == null
- ? folder.workspaceId
- : folder.parentFolderId,
- children:
- typeof folder.positions != null && typeof folder.positions !== 'string'
- ? folder.positions.orderedIds
- : [],
- })
- })
-
- docs.forEach((doc) => {
- const docId = getDocId(doc)
- const href = `${process.env.BOOST_HUB_BASE_URL}${getDocLinkHref(
- doc,
- team,
- 'index'
- )}`
- items.set(docId, {
- id: docId,
- lastUpdated: doc.head != null ? doc.head.created : doc.updatedAt,
- label: getDocTitle(doc, 'Untitled'),
- bookmarked: doc.bookmarked,
- emoji: doc.emoji,
- defaultIcon: mdiFileDocumentOutline,
- archived: doc.archivedAt != null,
- children: [],
- href,
- active: href === currentPathWithDomain,
- dropAround: sortingOrder === 'drag' ? true : false,
- navigateTo: () => push(href),
- onDrop: (position: SidebarDragState) =>
- dropInFolderOrDoc({ type: 'doc', result: doc }, position),
- onDragStart: () => {
- draggedResource.current = { type: 'doc', result: doc }
- },
- onDragEnd: () => {
- draggedResource.current = undefined
- },
- contextControls: [
- {
- type: MenuTypes.Normal,
- icon: doc.bookmarked ? mdiStar : mdiStarOutline,
- label:
- treeSendingMap.get(doc.id) === 'bookmark'
- ? '...'
- : doc.bookmarked
- ? 'Bookmarked'
- : 'Bookmark',
- onClick: () => toggleDocBookmark(doc.teamId, doc.id, doc.bookmarked),
- },
- {
- type: MenuTypes.Normal,
- icon: mdiPencil,
- label: 'Rename',
- onClick: () => openRenameDocForm(doc),
- },
- {
- type: MenuTypes.Normal,
- icon: mdiArchiveOutline,
- label: doc.archivedAt == null ? 'Archive' : 'Restore',
- onClick: () => toggleDocArchive(doc.teamId, doc.id, doc.archivedAt),
- },
- ],
- parentId:
- doc.parentFolderId == null ? doc.workspaceId : doc.parentFolderId,
- })
- })
-
- const arrayItems = getMapValues(items)
- const tree: Partial[] = []
-
- const bookmarked = arrayItems.reduce((acc, val) => {
- if (!val.bookmarked) {
- return acc
- }
-
- acc.push({
- id: val.id,
- depth: 0,
- label: val.label,
- emoji: val.emoji,
- defaultIcon: val.defaultIcon,
- href: val.href,
- navigateTo: val.navigateTo,
- contextControls: val.contextControls,
- })
- return acc
- }, [] as SidebarTreeChildRow[])
-
- const navTree = arrayItems
- .filter((item) => item.parentId == null)
- .reduce((acc, val) => {
- acc.push({
- ...val,
- depth: 0,
- rows: buildChildrenNavRows(sortingOrder, val.children, 1, items),
- })
- return acc
- }, [] as SidebarTreeChildRow[])
-
- const docsPerTagIdMap = [...docsMap.values()].reduce((acc, doc) => {
- const docTags = doc.tags || []
- docTags.forEach((tag) => {
- let docIds = acc.get(tag.id)
- if (docIds == null) {
- docIds = []
- acc.set(tag.id, docIds)
- }
- docIds.push(doc.id)
- })
- return acc
- }, new Map())
-
- const labels = getMapValues(tagsMap)
- .filter((tag) => (docsPerTagIdMap.get(tag.id) || []).length > 0)
- .sort((a, b) => {
- if (a.text < b.text) {
- return -1
- } else {
- return 1
- }
- })
- .reduce((acc, val) => {
- const href = `${process.env.BOOST_HUB_BASE_URL}${getTagHref(
- val,
- team,
- 'index'
- )}`
- acc.push({
- id: val.id,
- depth: 0,
- label: val.text,
- defaultIcon: mdiTag,
- href,
- active: href === currentPathWithDomain,
- navigateTo: () => push(href),
- })
- return acc
- }, [] as SidebarTreeChildRow[])
-
- if (bookmarked.length > 0) {
- tree.push({
- label: 'Bookmarks',
- rows: bookmarked,
- })
- }
- tree.push({
- label: 'Workspaces',
- rows: navTree,
- controls: [
- {
- icon: mdiPlus,
- onClick: () => openModal( ),
- },
- ],
- })
-
- if (!team.personal) {
- tree.push({
- label: 'Private',
- rows:
- personalWorkspace != null
- ? arrayItems
- .filter((item) => item.parentId === personalWorkspace!.id)
- .reduce((acc, val) => {
- acc.push({
- ...val,
- depth: 0,
- rows: buildChildrenNavRows(
- sortingOrder,
- val.children,
- 1,
- items
- ),
- })
- return acc
- }, [] as SidebarTreeChildRow[])
- : [],
- controls: [
- {
- icon: mdiFilePlusOutline,
- onClick: undefined,
- placeholder: 'Doc title..',
- create: async (title: string) => {
- if (personalWorkspace == null) {
- return createWorkspace(
- team,
- {
- personal: true,
- name: 'Private',
- permissions: [],
- public: false,
- },
- {
- skipRedirect: true,
- afterSuccess: (wp) =>
- createDoc(team, {
- workspaceId: wp.id,
- title,
- }),
- }
- )
- }
-
- return createDoc(team, {
- workspaceId: personalWorkspace!.id,
- title,
- })
- },
- },
- {
- icon: mdiFolderPlusOutline,
- onClick: undefined,
- placeholder: 'Folder name..',
- create: async (folderName: string) => {
- if (personalWorkspace == null) {
- return createWorkspace(
- team,
- {
- personal: true,
- name: 'Private',
- permissions: [],
- public: false,
- },
- {
- skipRedirect: true,
- afterSuccess: (wp) =>
- createFolder(team, {
- workspaceId: wp.id,
- description: '',
- folderName,
- }),
- }
- )
- }
-
- return createFolder(team, {
- workspaceId: personalWorkspace!.id,
- description: '',
- folderName,
- })
- },
- },
- ],
- })
- }
-
- if (labels.length > 0) {
- tree.push({
- label: 'Labels',
- rows: labels,
- })
- }
-
- tree.push({
- label: 'More',
- rows: [
- {
- id: 'sidenav-attachment',
- label: 'Attachments',
- defaultIcon: mdiPaperclip,
- href: getTeamLinkHref(team, 'uploads'),
- active: getTeamLinkHref(team, 'uploads') === currentPath,
- navigateTo: () => push(getTeamLinkHref(team, 'uploads')),
- depth: 0,
- },
- {
- id: 'sidenav-shared',
- label: 'Shared',
- defaultIcon: mdiWeb,
- href: getTeamLinkHref(team, 'shared'),
- active: getTeamLinkHref(team, 'shared') === currentPath,
- navigateTo: () => push(getTeamLinkHref(team, 'shared')),
- depth: 0,
- },
- {
- id: 'sidenav-archived',
- label: 'Archived',
- defaultIcon: mdiArchiveOutline,
- href: getTeamLinkHref(team, 'archived'),
- active: getTeamLinkHref(team, 'archived') === currentPath,
- navigateTo: () => push(getTeamLinkHref(team, 'archived')),
- depth: 0,
- },
- ],
- })
-
- tree.forEach((category) => {
- const key = (category.label || '').toLocaleLowerCase()
- const foldKey = `fold-${key}`
- const hideKey = `hide-${key}`
- category.folded = sideBarOpenedLinksIdsSet.has(foldKey)
- category.folding = getFoldEvents('links', foldKey, true)
- category.hidden = sideBarOpenedLinksIdsSet.has(hideKey)
- category.toggleHidden = () => toggleItem('links', hideKey)
- })
-
- return tree as SidebarNavCategory[]
-}
-
function mapToolbarRows(
showSpaces: boolean,
setShowSpaces: React.Dispatch>,
@@ -1546,73 +764,6 @@ function buildSpacesBottomRows(push: (url: string) => void) {
]
}
-function buildChildrenNavRows(
- sortingOrder: SidebarTreeSortingOrder,
- childrenIds: string[],
- depth: number,
- map: Map
-) {
- const rows = childrenIds.reduce((acc, childId) => {
- const childRow = map.get(childId)
- if (childRow == null) {
- return acc
- }
-
- if (childRow.archived) {
- return acc
- }
-
- acc.push({
- ...childRow,
- depth,
- rows: buildChildrenNavRows(
- sortingOrder,
- childRow.children,
- depth + 1,
- map
- ),
- })
-
- return acc
- }, [] as (SidebarTreeChildRow & { lastUpdated: string })[])
-
- switch (sortingOrder) {
- case 'a-z':
- return sortByAttributeAsc('label', rows)
- case 'z-a':
- return sortByAttributeDesc('label', rows)
- case 'last-updated':
- return sortByAttributeDesc('lastUpdated', rows)
- case 'drag':
- default:
- return rows
- }
-}
-
-type CloudTreeItem = {
- id: string
- parentId?: string
- label: string
- defaultIcon?: string
- emoji?: string
- bookmarked?: boolean
- archived?: boolean
- children: string[]
- folding?: FoldingProps
- folded?: boolean
- href?: string
- active?: boolean
- lastUpdated: string
- navigateTo?: () => void
- controls?: SidebarNavControls[]
- contextControls?: MenuItem[]
- dropIn?: boolean
- dropAround?: boolean
- onDragStart?: () => void
- onDrop?: (position?: SidebarDragState) => void
- onDragEnd?: () => void
-}
-
function isCodeMirrorTextAreaEvent(event: KeyboardEvent) {
const target = event.target as HTMLTextAreaElement
if (target == null || target.tagName.toLowerCase() !== 'textarea') {
diff --git a/src/cloud/components/molecules/Editor/index.tsx b/src/cloud/components/molecules/Editor/index.tsx
index 89dbeb8d34..30b453ddd3 100644
--- a/src/cloud/components/molecules/Editor/index.tsx
+++ b/src/cloud/components/molecules/Editor/index.tsx
@@ -73,8 +73,8 @@ import { useToast } from '../../../../shared/lib/stores/toast'
import { LoadingButton } from '../../../../shared/components/atoms/Button'
import { trackEvent } from '../../../api/track'
import { MixpanelActionTrackTypes } from '../../../interfaces/analytics/mixpanel'
-import { useCloudUpdater } from '../../../lib/hooks/useCloudUpdater'
-import { useCloudUI } from '../../../lib/hooks/useCloudUI'
+import { useCloudApi } from '../../../lib/hooks/useCloudApi'
+import { useCloudResourceModals } from '../../../lib/hooks/useCloudResourceModals'
import { mapTopbarBreadcrumbs } from '../../../lib/mappers/topbarBreadcrumbs'
import { useModal } from '../../../../shared/lib/stores/modal'
@@ -151,7 +151,7 @@ const Editor = ({
})
const { docsMap, workspacesMap, foldersMap } = useNav()
const suggestionsRef = useRef([])
- const { sendingMap, toggleDocBookmark } = useCloudUpdater()
+ const { sendingMap, toggleDocBookmark } = useCloudApi()
const {
openRenameDocForm,
openRenameFolderForm,
@@ -161,7 +161,7 @@ const Editor = ({
deleteOrArchiveDoc,
deleteFolder,
deleteWorkspace,
- } = useCloudUI()
+ } = useCloudResourceModals()
const userInfo = useMemo(() => {
return {
diff --git a/src/cloud/components/molecules/NewDocButton.tsx b/src/cloud/components/molecules/NewDocButton.tsx
index 682484b267..243231732f 100644
--- a/src/cloud/components/molecules/NewDocButton.tsx
+++ b/src/cloud/components/molecules/NewDocButton.tsx
@@ -13,7 +13,7 @@ import {
import { useModal } from '../../../shared/lib/stores/modal'
import styled from '../../../shared/lib/styled'
import { SerializedTeam } from '../../interfaces/db/team'
-import { useCloudUI } from '../../lib/hooks/useCloudUI'
+import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals'
import { useNav } from '../../lib/stores/nav'
import TemplatesModal from '../organisms/Modal/contents/TemplatesModal'
@@ -24,7 +24,7 @@ const NewDocButton = ({ team }: { team: SerializedTeam }) => {
currentPath,
currentParentFolderId,
} = useNav()
- const { openNewDocForm } = useCloudUI()
+ const { openNewDocForm } = useCloudResourceModals()
const { popup } = useContextMenu()
const { openModal } = useModal()
diff --git a/src/cloud/components/organisms/DocPage/View.tsx b/src/cloud/components/organisms/DocPage/View.tsx
index cef0725d74..dc24bc44d0 100644
--- a/src/cloud/components/organisms/DocPage/View.tsx
+++ b/src/cloud/components/organisms/DocPage/View.tsx
@@ -26,8 +26,8 @@ import { useToast } from '../../../../shared/lib/stores/toast'
import { useRouter } from '../../../lib/router'
import { LoadingButton } from '../../../../shared/components/atoms/Button'
import { mdiStar, mdiStarOutline } from '@mdi/js'
-import { useCloudUpdater } from '../../../lib/hooks/useCloudUpdater'
-import { useCloudUI } from '../../../lib/hooks/useCloudUI'
+import { useCloudApi } from '../../../lib/hooks/useCloudApi'
+import { useCloudResourceModals } from '../../../lib/hooks/useCloudResourceModals'
import { mapTopbarBreadcrumbs } from '../../../lib/mappers/topbarBreadcrumbs'
interface ViewPageProps {
@@ -56,7 +56,7 @@ const ViewPage = ({
const { setPartialPageData, currentUserPermissions } = usePage()
const { pushMessage } = useToast()
const { preferences } = usePreferences()
- const { sendingMap, toggleDocBookmark } = useCloudUpdater()
+ const { sendingMap, toggleDocBookmark } = useCloudApi()
const {
openRenameDocForm,
openRenameFolderForm,
@@ -66,7 +66,7 @@ const ViewPage = ({
deleteOrArchiveDoc: deleteDoc,
deleteFolder,
deleteWorkspace,
- } = useCloudUI()
+ } = useCloudResourceModals()
const unarchiveHandler = useCallback(async () => {
try {
diff --git a/src/cloud/components/organisms/FolderPage/index.tsx b/src/cloud/components/organisms/FolderPage/index.tsx
index a5fb965eeb..8dce741c0f 100644
--- a/src/cloud/components/organisms/FolderPage/index.tsx
+++ b/src/cloud/components/organisms/FolderPage/index.tsx
@@ -33,8 +33,8 @@ import { useRouter } from '../../../lib/router'
import { LoadingButton } from '../../../../shared/components/atoms/Button'
import FolderContextMenu from '../Topbar/Controls/ControlsContextMenu/FolderContextMenu'
import FlattenedBreadcrumbs from '../../../../shared/components/molecules/FlattenedBreadcrumbs'
-import { useCloudUI } from '../../../lib/hooks/useCloudUI'
-import { useCloudUpdater } from '../../../lib/hooks/useCloudUpdater'
+import { useCloudResourceModals } from '../../../lib/hooks/useCloudResourceModals'
+import { useCloudApi } from '../../../lib/hooks/useCloudApi'
import { mapTopbarBreadcrumbs } from '../../../lib/mappers/topbarBreadcrumbs'
enum FolderHeaderActions {
@@ -53,7 +53,7 @@ const FolderPage = () => {
} = useNav()
const { openEmojiPicker } = useEmojiPicker()
const [sending, setSending] = useState()
- const { toggleFolderBookmark, sendingMap } = useCloudUpdater()
+ const { toggleFolderBookmark, sendingMap } = useCloudApi()
const { push } = useRouter()
const [showContextMenu, setShowContextMenu] = useState(false)
const {
@@ -65,7 +65,7 @@ const FolderPage = () => {
openWorkspaceEditForm,
deleteOrArchiveDoc,
deleteWorkspace,
- } = useCloudUI()
+ } = useCloudResourceModals()
const currentFolder = useMemo(() => {
if (pageFolder == null) {
diff --git a/src/cloud/components/organisms/Sidebar/SideNavigator/SideNavigatorFolderControls.tsx b/src/cloud/components/organisms/Sidebar/SideNavigator/SideNavigatorFolderControls.tsx
index 5e40836a21..beb56528fc 100644
--- a/src/cloud/components/organisms/Sidebar/SideNavigator/SideNavigatorFolderControls.tsx
+++ b/src/cloud/components/organisms/Sidebar/SideNavigator/SideNavigatorFolderControls.tsx
@@ -36,7 +36,7 @@ import SideNavigatorIconButton from './SideNavigatorIconButton'
import Tooltip from '../../../atoms/Tooltip'
import IconMdi from '../../../atoms/IconMdi'
import { useToast } from '../../../../../shared/lib/stores/toast'
-import { useCloudUI } from '../../../../lib/hooks/useCloudUI'
+import { useCloudResourceModals } from '../../../../lib/hooks/useCloudResourceModals'
interface SideNavigatorFolderControlsProps {
folder: SerializedFolderWithBookmark
@@ -53,7 +53,7 @@ const SideNavigatorFolderControls = ({
const { pushMessage, pushApiErrorMessage } = useToast()
const { popup } = useContextMenu()
const [sendingBookmark, setSendingBookmark] = useState(false)
- const { openRenameFolderForm } = useCloudUI()
+ const { openRenameFolderForm } = useCloudResourceModals()
const toggleBookmark = useCallback(async () => {
if (sendingBookmark) {
diff --git a/src/cloud/components/organisms/Sidebar/SidebarWorkspaces/SideNavigatorWorkspaceControls.tsx b/src/cloud/components/organisms/Sidebar/SidebarWorkspaces/SideNavigatorWorkspaceControls.tsx
index 622ac858a7..6999b2e1e9 100644
--- a/src/cloud/components/organisms/Sidebar/SidebarWorkspaces/SideNavigatorWorkspaceControls.tsx
+++ b/src/cloud/components/organisms/Sidebar/SidebarWorkspaces/SideNavigatorWorkspaceControls.tsx
@@ -26,7 +26,7 @@ import { useGlobalData } from '../../../../lib/stores/globalData'
import { usePage } from '../../../../lib/stores/pageStore'
import IconMdi from '../../../atoms/IconMdi'
import { useToast } from '../../../../../shared/lib/stores/toast'
-import { useCloudUI } from '../../../../lib/hooks/useCloudUI'
+import { useCloudResourceModals } from '../../../../lib/hooks/useCloudResourceModals'
interface SideNavigatorWorkspaceControlsProps {
workspace: SerializedWorkspace
@@ -57,7 +57,7 @@ const SideNavigatorWorkspaceControls = ({
const { popup } = useContextMenu()
const { messageBox } = useDialog()
const { pushApiErrorMessage, pushMessage } = useToast()
- const { openWorkspaceEditForm } = useCloudUI()
+ const { openWorkspaceEditForm } = useCloudResourceModals()
const createChildDoc = useCallback(async () => {
try {
diff --git a/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx b/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx
index 43ab53861c..6907843e54 100644
--- a/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx
+++ b/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx
@@ -29,7 +29,7 @@ import { MetaKeyText } from '../../../../../lib/keyboard'
import IconMdi from '../../../../atoms/IconMdi'
import { mdiStar, mdiTrashCan, mdiStarOutline, mdiPencil } from '@mdi/js'
import { useToast } from '../../../../../../shared/lib/stores/toast'
-import { useCloudUI } from '../../../../../lib/hooks/useCloudUI'
+import { useCloudResourceModals } from '../../../../../lib/hooks/useCloudResourceModals'
interface FolderContextMenuProps {
currentFolder: SerializedFolderWithBookmark
@@ -44,7 +44,7 @@ const FolderContextMenu = ({
const { updateFoldersMap, deleteFolderHandler } = useNav()
const { setPartialPageData } = usePage()
const { pushMessage } = useToast()
- const { openRenameFolderForm } = useCloudUI()
+ const { openRenameFolderForm } = useCloudResourceModals()
const menuRef = React.createRef()
useEffectOnce(() => {
diff --git a/src/cloud/components/organisms/WorkspacePage/index.tsx b/src/cloud/components/organisms/WorkspacePage/index.tsx
index 863d0369b5..26248f4c9d 100644
--- a/src/cloud/components/organisms/WorkspacePage/index.tsx
+++ b/src/cloud/components/organisms/WorkspacePage/index.tsx
@@ -13,7 +13,7 @@ import ContentManager from '../../molecules/ContentManager'
import Application from '../../Application'
import { useRouter } from '../../../lib/router'
import FlattenedBreadcrumbs from '../../../../shared/components/molecules/FlattenedBreadcrumbs'
-import { useCloudUI } from '../../../lib/hooks/useCloudUI'
+import { useCloudResourceModals } from '../../../lib/hooks/useCloudResourceModals'
import { mapWorkspaceBreadcrumb } from '../../../lib/mappers/topbarBreadcrumbs'
interface WorkspacePage {
@@ -35,7 +35,7 @@ const WorkspacePage = ({ workspace }: WorkspacePage) => {
openNewDocForm,
openWorkspaceEditForm,
deleteWorkspace,
- } = useCloudUI()
+ } = useCloudResourceModals()
const topbarBreadcrumbs = useMemo(() => {
if (team == null) {
diff --git a/src/cloud/lib/hooks/useCloudDnd.ts b/src/cloud/lib/hooks/sidebar/useCloudSidebarDnd.ts
similarity index 82%
rename from src/cloud/lib/hooks/useCloudDnd.ts
rename to src/cloud/lib/hooks/sidebar/useCloudSidebarDnd.ts
index afe229b13a..061fee1598 100644
--- a/src/cloud/lib/hooks/useCloudDnd.ts
+++ b/src/cloud/lib/hooks/sidebar/useCloudSidebarDnd.ts
@@ -1,18 +1,18 @@
import { useCallback, useRef } from 'react'
-import { UpdateDocRequestBody } from '../../api/teams/docs'
-import { UpdateFolderRequestBody } from '../../api/teams/folders'
-import { moveResource } from '../../api/teams/resources'
-import { SerializedDoc } from '../../interfaces/db/doc'
-import { SerializedFolder } from '../../interfaces/db/folder'
-import { NavResource } from '../../interfaces/resources'
-import { useNav } from '../stores/nav'
-import { usePage } from '../stores/pageStore'
-import { getResourceId } from '../utils/patterns'
-import { SidebarDragState } from '../../../shared/lib/dnd'
-import { useToast } from '../../../shared/lib/stores/toast'
-import { getMapFromEntityArray } from '../../../shared/lib/utils/array'
+import { UpdateDocRequestBody } from '../../../api/teams/docs'
+import { UpdateFolderRequestBody } from '../../../api/teams/folders'
+import { moveResource } from '../../../api/teams/resources'
+import { SerializedDoc } from '../../../interfaces/db/doc'
+import { SerializedFolder } from '../../../interfaces/db/folder'
+import { NavResource } from '../../../interfaces/resources'
+import { useNav } from '../../stores/nav'
+import { usePage } from '../../stores/pageStore'
+import { getResourceId } from '../../utils/patterns'
+import { SidebarDragState } from '../../../../shared/lib/dnd'
+import { useToast } from '../../../../shared/lib/stores/toast'
+import { getMapFromEntityArray } from '../../../../shared/lib/utils/array'
-export function useCloudDnd() {
+export function useCloudSidebarDnd() {
const draggedCategory = useRef()
const draggedResource = useRef()
const {
diff --git a/src/cloud/lib/hooks/sidebar/useCloudSidebarTree.tsx b/src/cloud/lib/hooks/sidebar/useCloudSidebarTree.tsx
new file mode 100644
index 0000000000..98b9dfefa2
--- /dev/null
+++ b/src/cloud/lib/hooks/sidebar/useCloudSidebarTree.tsx
@@ -0,0 +1,802 @@
+import React, { useCallback, useMemo } from 'react'
+import {
+ mdiApplicationCog,
+ mdiArchiveOutline,
+ mdiFileDocumentOutline,
+ mdiFilePlusOutline,
+ mdiFolderPlusOutline,
+ mdiLock,
+ mdiPaperclip,
+ mdiPencil,
+ mdiPlus,
+ mdiStar,
+ mdiStarOutline,
+ mdiTag,
+ mdiTrashCanOutline,
+ mdiWeb,
+} from '@mdi/js'
+import { FoldingProps } from '../../../../shared/components/atoms/FoldingWrapper'
+import {
+ SidebarNavCategory,
+ SidebarNavControls,
+ SidebarTreeChildRow,
+} from '../../../../shared/components/organisms/Sidebar/molecules/SidebarTree'
+import { SidebarDragState } from '../../../../shared/lib/dnd'
+import { SidebarTreeSortingOrder } from '../../../../shared/lib/sidebar'
+import { MenuItem, MenuTypes } from '../../../../shared/lib/stores/contextMenu'
+import { useModal } from '../../../../shared/lib/stores/modal'
+import {
+ getMapValues,
+ sortByAttributeAsc,
+ sortByAttributeDesc,
+} from '../../../../shared/lib/utils/array'
+import { getDocLinkHref } from '../../../components/atoms/Link/DocLink'
+import { getFolderHref } from '../../../components/atoms/Link/FolderLink'
+import { getTagHref } from '../../../components/atoms/Link/TagLink'
+import { getTeamLinkHref } from '../../../components/atoms/Link/TeamLink'
+import { getWorkspaceHref } from '../../../components/atoms/Link/WorkspaceLink'
+import CreateWorkspaceModal from '../../../components/organisms/Modal/contents/Workspace/CreateWorkspaceModal'
+import { SerializedWorkspace } from '../../../interfaces/db/workspace'
+import { useRouter } from '../../router'
+import {
+ cloudSidebaCategoryLabels,
+ cloudSidebarOrderedCategoriesDelimiter,
+} from '../../sidebar'
+import { useNav } from '../../stores/nav'
+import { usePage } from '../../stores/pageStore'
+import { usePreferences } from '../../stores/preferences'
+import {
+ CollapsableType,
+ useSidebarCollapse,
+} from '../../stores/sidebarCollapse'
+import { getDocId, getDocTitle, getFolderId } from '../../utils/patterns'
+import { useCloudApi } from '../useCloudApi'
+import { useCloudResourceModals } from '../useCloudResourceModals'
+import { useCloudSidebarDnd } from './useCloudSidebarDnd'
+
+export function useCloudSidebarTree() {
+ const { team } = usePage()
+ const { push, pathname } = useRouter()
+ const { openModal } = useModal()
+ const { preferences, setPreferences } = usePreferences()
+
+ const {
+ initialLoadDone,
+ tagsMap,
+ docsMap,
+ foldersMap,
+ workspacesMap,
+ } = useNav()
+
+ const {
+ sideBarOpenedLinksIdsSet,
+ sideBarOpenedFolderIdsSet,
+ sideBarOpenedWorkspaceIdsSet,
+ toggleItem,
+ unfoldItem,
+ foldItem,
+ } = useSidebarCollapse()
+
+ const {
+ draggedCategory,
+ draggedResource,
+ dropInDocOrFolder,
+ dropInWorkspace,
+ } = useCloudSidebarDnd()
+
+ const {
+ sendingMap: treeSendingMap,
+ createWorkspace,
+ createDoc,
+ createFolder,
+ toggleDocArchive,
+ toggleDocBookmark,
+ toggleFolderBookmark,
+ updateDoc,
+ updateFolder,
+ } = useCloudApi()
+
+ const {
+ deleteWorkspace,
+ deleteFolder,
+ openRenameFolderForm,
+ openRenameDocForm,
+ openWorkspaceEditForm,
+ } = useCloudResourceModals()
+
+ const getFoldEvents = useCallback(
+ (type: CollapsableType, key: string, reversed?: boolean) => {
+ if (reversed) {
+ return {
+ fold: () => unfoldItem(type, key),
+ unfold: () => foldItem(type, key),
+ toggle: () => toggleItem(type, key),
+ }
+ }
+
+ return {
+ fold: () => foldItem(type, key),
+ unfold: () => unfoldItem(type, key),
+ toggle: () => toggleItem(type, key),
+ }
+ },
+ [toggleItem, unfoldItem, foldItem]
+ )
+
+ const tree = useMemo(() => {
+ if (!initialLoadDone || team == null) {
+ return undefined
+ }
+
+ const currentPathWithDomain = `${process.env.BOOST_HUB_BASE_URL}${pathname}`
+ const items = new Map()
+
+ const [docs, folders, workspaces] = [
+ getMapValues(docsMap),
+ getMapValues(foldersMap),
+ getMapValues(workspacesMap),
+ ]
+
+ let personalWorkspace: SerializedWorkspace | undefined
+ workspaces.forEach((wp) => {
+ if (wp.personal) {
+ personalWorkspace = wp
+ return
+ }
+
+ const href = `${process.env.BOOST_HUB_BASE_URL}${getWorkspaceHref(
+ wp,
+ team,
+ 'index'
+ )}`
+ items.set(wp.id, {
+ id: wp.id,
+ lastUpdated: wp.updatedAt,
+ label: wp.name,
+ defaultIcon: !wp.public ? mdiLock : undefined,
+ children: wp.positions?.orderedIds || [],
+ folded: !sideBarOpenedWorkspaceIdsSet.has(wp.id),
+ folding: getFoldEvents('workspaces', wp.id),
+ href,
+ active: href === currentPathWithDomain,
+ navigateTo: () => push(href),
+ dropIn: true,
+ onDrop: () => dropInWorkspace(wp.id, updateFolder, updateDoc),
+ controls: [
+ {
+ icon: mdiFilePlusOutline,
+ onClick: undefined,
+ placeholder: 'Doc title..',
+ create: (title: string) =>
+ createDoc(team, {
+ workspaceId: wp.id,
+ title,
+ }),
+ },
+ {
+ icon: mdiFolderPlusOutline,
+ onClick: undefined,
+ placeholder: 'Folder name..',
+ create: (folderName: string) =>
+ createFolder(team, {
+ workspaceId: wp.id,
+ description: '',
+ folderName,
+ }),
+ },
+ ],
+ contextControls: wp.default
+ ? [
+ {
+ type: MenuTypes.Normal,
+ icon: mdiApplicationCog,
+ label: 'Edit',
+ onClick: () => openWorkspaceEditForm(wp),
+ },
+ ]
+ : [
+ {
+ type: MenuTypes.Normal,
+ icon: mdiApplicationCog,
+ label: 'Edit',
+ onClick: () => openWorkspaceEditForm(wp),
+ },
+ {
+ type: MenuTypes.Normal,
+ icon: mdiTrashCanOutline,
+ label: 'Delete',
+ onClick: () => deleteWorkspace(wp),
+ },
+ ],
+ })
+ })
+
+ folders.forEach((folder) => {
+ const folderId = getFolderId(folder)
+ const href = `${process.env.BOOST_HUB_BASE_URL}${getFolderHref(
+ folder,
+ team,
+ 'index'
+ )}`
+ items.set(folderId, {
+ id: folderId,
+ lastUpdated: folder.updatedAt,
+ label: folder.name,
+ bookmarked: folder.bookmarked,
+ emoji: folder.emoji,
+ folded: !sideBarOpenedFolderIdsSet.has(folder.id),
+ folding: getFoldEvents('folders', folder.id),
+ href,
+ active: href === currentPathWithDomain,
+ navigateTo: () => push(href),
+ onDrop: (position: SidebarDragState) =>
+ dropInDocOrFolder({ type: 'folder', result: folder }, position),
+ onDragStart: () => {
+ draggedResource.current = { type: 'folder', result: folder }
+ },
+ onDragEnd: () => {
+ draggedResource.current = undefined
+ },
+ dropIn: true,
+ dropAround:
+ preferences.sidebarTreeSortingOrder === 'drag' ? true : false,
+ controls: [
+ {
+ icon: mdiFilePlusOutline,
+ onClick: undefined,
+ placeholder: 'Doc title..',
+ create: (title: string) =>
+ createDoc(team, {
+ parentFolderId: folder.id,
+ workspaceId: folder.workspaceId,
+ title,
+ }),
+ },
+ {
+ icon: mdiFolderPlusOutline,
+ onClick: undefined,
+ placeholder: 'Folder name..',
+ create: (folderName: string) =>
+ createFolder(team, {
+ parentFolderId: folder.id,
+ workspaceId: folder.workspaceId,
+ description: '',
+ folderName,
+ }),
+ },
+ ],
+ contextControls: [
+ {
+ type: MenuTypes.Normal,
+ icon: folder.bookmarked ? mdiStar : mdiStarOutline,
+ label:
+ treeSendingMap.get(folder.id) === 'bookmark'
+ ? '...'
+ : folder.bookmarked
+ ? 'Bookmarked'
+ : 'Bookmark',
+ onClick: () =>
+ toggleFolderBookmark(folder.teamId, folder.id, folder.bookmarked),
+ },
+ {
+ type: MenuTypes.Normal,
+ icon: mdiPencil,
+ label: 'Rename',
+ onClick: () => openRenameFolderForm(folder),
+ },
+ {
+ type: MenuTypes.Normal,
+ icon: mdiTrashCanOutline,
+ label: 'Delete',
+ onClick: () => deleteFolder(folder),
+ },
+ ],
+ parentId:
+ folder.parentFolderId == null
+ ? folder.workspaceId
+ : folder.parentFolderId,
+ children:
+ typeof folder.positions != null &&
+ typeof folder.positions !== 'string'
+ ? folder.positions.orderedIds
+ : [],
+ })
+ })
+
+ docs.forEach((doc) => {
+ const docId = getDocId(doc)
+ const href = `${process.env.BOOST_HUB_BASE_URL}${getDocLinkHref(
+ doc,
+ team,
+ 'index'
+ )}`
+ items.set(docId, {
+ id: docId,
+ lastUpdated: doc.head != null ? doc.head.created : doc.updatedAt,
+ label: getDocTitle(doc, 'Untitled'),
+ bookmarked: doc.bookmarked,
+ emoji: doc.emoji,
+ defaultIcon: mdiFileDocumentOutline,
+ archived: doc.archivedAt != null,
+ children: [],
+ href,
+ active: href === currentPathWithDomain,
+ dropAround:
+ preferences.sidebarTreeSortingOrder === 'drag' ? true : false,
+ navigateTo: () => push(href),
+ onDrop: (position: SidebarDragState) =>
+ dropInDocOrFolder({ type: 'doc', result: doc }, position),
+ onDragStart: () => {
+ draggedResource.current = { type: 'doc', result: doc }
+ },
+ onDragEnd: () => {
+ draggedResource.current = undefined
+ },
+ contextControls: [
+ {
+ type: MenuTypes.Normal,
+ icon: doc.bookmarked ? mdiStar : mdiStarOutline,
+ label:
+ treeSendingMap.get(doc.id) === 'bookmark'
+ ? '...'
+ : doc.bookmarked
+ ? 'Bookmarked'
+ : 'Bookmark',
+ onClick: () =>
+ toggleDocBookmark(doc.teamId, doc.id, doc.bookmarked),
+ },
+ {
+ type: MenuTypes.Normal,
+ icon: mdiPencil,
+ label: 'Rename',
+ onClick: () => openRenameDocForm(doc),
+ },
+ {
+ type: MenuTypes.Normal,
+ icon: mdiArchiveOutline,
+ label: doc.archivedAt == null ? 'Archive' : 'Restore',
+ onClick: () => toggleDocArchive(doc.teamId, doc.id, doc.archivedAt),
+ },
+ ],
+ parentId:
+ doc.parentFolderId == null ? doc.workspaceId : doc.parentFolderId,
+ })
+ })
+
+ const arrayItems = getMapValues(items)
+ const tree: Partial[] = []
+
+ let orderedBookmarked = []
+ const bookmarked = arrayItems.reduce((acc, val) => {
+ if (!val.bookmarked) {
+ return acc
+ }
+
+ acc.push({
+ id: val.id,
+ depth: 0,
+ label: val.label,
+ emoji: val.emoji,
+ defaultIcon: val.defaultIcon,
+ href: val.href,
+ navigateTo: val.navigateTo,
+ contextControls: val.contextControls,
+ lastUpdated: val.lastUpdated,
+ })
+
+ return acc
+ }, [] as (SidebarTreeChildRow & { lastUpdated: string })[])
+
+ switch (preferences.sidebarTreeSortingOrder) {
+ case 'a-z':
+ orderedBookmarked = sortByAttributeAsc('label', bookmarked)
+ break
+ case 'z-a':
+ orderedBookmarked = sortByAttributeDesc('label', bookmarked)
+ break
+ case 'last-updated':
+ orderedBookmarked = sortByAttributeDesc('lastUpdated', bookmarked)
+ break
+ case 'drag':
+ default:
+ orderedBookmarked = bookmarked
+ break
+ }
+
+ const navTree = arrayItems
+ .filter((item) => item.parentId == null)
+ .reduce((acc, val) => {
+ acc.push({
+ ...val,
+ depth: 0,
+ rows: buildChildrenNavRows(
+ preferences.sidebarTreeSortingOrder,
+ val.children,
+ 1,
+ items
+ ),
+ })
+ return acc
+ }, [] as SidebarTreeChildRow[])
+
+ const docsPerTagIdMap = [...docsMap.values()].reduce((acc, doc) => {
+ const docTags = doc.tags || []
+ docTags.forEach((tag) => {
+ let docIds = acc.get(tag.id)
+ if (docIds == null) {
+ docIds = []
+ acc.set(tag.id, docIds)
+ }
+ docIds.push(doc.id)
+ })
+ return acc
+ }, new Map())
+
+ const labels = getMapValues(tagsMap)
+ .filter((tag) => (docsPerTagIdMap.get(tag.id) || []).length > 0)
+ .sort((a, b) => {
+ if (a.text < b.text) {
+ return -1
+ } else {
+ return 1
+ }
+ })
+ .reduce((acc, val) => {
+ const href = `${process.env.BOOST_HUB_BASE_URL}${getTagHref(
+ val,
+ team,
+ 'index'
+ )}`
+ acc.push({
+ id: val.id,
+ depth: 0,
+ label: val.text,
+ defaultIcon: mdiTag,
+ href,
+ active: href === currentPathWithDomain,
+ navigateTo: () => push(href),
+ })
+ return acc
+ }, [] as SidebarTreeChildRow[])
+
+ if (orderedBookmarked.length > 0) {
+ tree.push({
+ label: 'Bookmarks',
+ rows: orderedBookmarked,
+ })
+ }
+ tree.push({
+ label: 'Workspaces',
+ rows: navTree,
+ controls: [
+ {
+ icon: mdiPlus,
+ onClick: () => openModal( ),
+ },
+ ],
+ })
+
+ if (!team.personal) {
+ tree.push({
+ label: 'Private',
+ rows:
+ personalWorkspace != null
+ ? arrayItems
+ .filter((item) => item.parentId === personalWorkspace!.id)
+ .reduce((acc, val) => {
+ acc.push({
+ ...val,
+ depth: 0,
+ rows: buildChildrenNavRows(
+ preferences.sidebarTreeSortingOrder,
+ val.children,
+ 1,
+ items
+ ),
+ })
+ return acc
+ }, [] as SidebarTreeChildRow[])
+ : [],
+ controls: [
+ {
+ icon: mdiFilePlusOutline,
+ onClick: undefined,
+ placeholder: 'Doc title..',
+ create: async (title: string) => {
+ if (personalWorkspace == null) {
+ return createWorkspace(
+ team,
+ {
+ personal: true,
+ name: 'Private',
+ permissions: [],
+ public: false,
+ },
+ {
+ skipRedirect: true,
+ afterSuccess: (wp) =>
+ createDoc(team, {
+ workspaceId: wp.id,
+ title,
+ }),
+ }
+ )
+ }
+
+ return createDoc(team, {
+ workspaceId: personalWorkspace!.id,
+ title,
+ })
+ },
+ },
+ {
+ icon: mdiFolderPlusOutline,
+ onClick: undefined,
+ placeholder: 'Folder name..',
+ create: async (folderName: string) => {
+ if (personalWorkspace == null) {
+ return createWorkspace(
+ team,
+ {
+ personal: true,
+ name: 'Private',
+ permissions: [],
+ public: false,
+ },
+ {
+ skipRedirect: true,
+ afterSuccess: (wp) =>
+ createFolder(team, {
+ workspaceId: wp.id,
+ description: '',
+ folderName,
+ }),
+ }
+ )
+ }
+
+ return createFolder(team, {
+ workspaceId: personalWorkspace!.id,
+ description: '',
+ folderName,
+ })
+ },
+ },
+ ],
+ })
+ }
+
+ if (labels.length > 0) {
+ tree.push({
+ label: 'Labels',
+ rows: labels,
+ })
+ }
+
+ tree.push({
+ label: 'More',
+ rows: [
+ {
+ id: 'sidenav-attachment',
+ label: 'Attachments',
+ defaultIcon: mdiPaperclip,
+ href: getTeamLinkHref(team, 'uploads'),
+ active: getTeamLinkHref(team, 'uploads') === pathname,
+ navigateTo: () => push(getTeamLinkHref(team, 'uploads')),
+ depth: 0,
+ },
+ {
+ id: 'sidenav-shared',
+ label: 'Shared',
+ defaultIcon: mdiWeb,
+ href: getTeamLinkHref(team, 'shared'),
+ active: getTeamLinkHref(team, 'shared') === pathname,
+ navigateTo: () => push(getTeamLinkHref(team, 'shared')),
+ depth: 0,
+ },
+ {
+ id: 'sidenav-archived',
+ label: 'Archived',
+ defaultIcon: mdiArchiveOutline,
+ href: getTeamLinkHref(team, 'archived'),
+ active: getTeamLinkHref(team, 'archived') === pathname,
+ navigateTo: () => push(getTeamLinkHref(team, 'archived')),
+ depth: 0,
+ },
+ ],
+ })
+
+ tree.forEach((category) => {
+ const key = (category.label || '').toLocaleLowerCase()
+ const foldKey = `fold-${key}`
+ const hideKey = `hide-${key}`
+ category.folded = sideBarOpenedLinksIdsSet.has(foldKey)
+ category.folding = getFoldEvents('links', foldKey, true)
+ category.hidden = sideBarOpenedLinksIdsSet.has(hideKey)
+ category.toggleHidden = () => toggleItem('links', hideKey)
+ })
+
+ return tree as SidebarNavCategory[]
+ }, [
+ initialLoadDone,
+ preferences.sidebarTreeSortingOrder,
+ pathname,
+ docsMap,
+ foldersMap,
+ workspacesMap,
+ tagsMap,
+ treeSendingMap,
+ sideBarOpenedFolderIdsSet,
+ sideBarOpenedLinksIdsSet,
+ sideBarOpenedWorkspaceIdsSet,
+ toggleItem,
+ getFoldEvents,
+ push,
+ openModal,
+ toggleDocBookmark,
+ toggleFolderBookmark,
+ createWorkspace,
+ deleteWorkspace,
+ toggleDocArchive,
+ deleteFolder,
+ createFolder,
+ createDoc,
+ dropInDocOrFolder,
+ dropInWorkspace,
+ updateFolder,
+ updateDoc,
+ openRenameFolderForm,
+ openRenameDocForm,
+ openWorkspaceEditForm,
+ draggedResource,
+ team,
+ ])
+
+ const treeWithOrderedCategories = useMemo(() => {
+ if (tree == null) {
+ return undefined
+ }
+
+ const orderedCategories = Array.from(
+ new Set([
+ ...preferences.sidebarOrderedCategories.split(
+ cloudSidebarOrderedCategoriesDelimiter
+ ),
+ ...cloudSidebaCategoryLabels,
+ ])
+ ).filter((item) =>
+ cloudSidebaCategoryLabels.find((categoryLabel) => categoryLabel === item)
+ )
+
+ const orderedTree = tree.sort((categoryA, categoryB) => {
+ if (
+ orderedCategories.indexOf(categoryA.label) >
+ orderedCategories.indexOf(categoryB.label)
+ ) {
+ return 1
+ } else {
+ return -1
+ }
+ })
+
+ orderedTree.forEach((category) => {
+ category.drag = {
+ onDragStart: () => {
+ draggedCategory.current = category.label
+ },
+ onDragEnd: () => {
+ draggedCategory.current = undefined
+ },
+ onDrop: () => {
+ if (draggedCategory.current == null) {
+ return
+ }
+ const orderedItems = orderedCategories.splice(0)
+ const categoryIndex = orderedItems.includes(category.label)
+ ? orderedItems.indexOf(category.label)
+ : orderedItems.length - 1
+
+ const reArrangedArray = orderedItems.reduce((acc, val, i) => {
+ if (i === categoryIndex) {
+ acc.push(draggedCategory.current!)
+ }
+
+ if (i !== categoryIndex && val === draggedCategory.current) {
+ return acc
+ }
+
+ acc.push(val)
+ return acc
+ }, [] as string[])
+
+ setPreferences({
+ sidebarOrderedCategories: reArrangedArray.join(
+ cloudSidebarOrderedCategoriesDelimiter
+ ),
+ })
+
+ draggedCategory.current = undefined
+ },
+ }
+ })
+
+ return orderedTree
+ }, [
+ tree,
+ preferences.sidebarOrderedCategories,
+ setPreferences,
+ draggedCategory,
+ ])
+
+ return {
+ tree,
+ treeWithOrderedCategories,
+ }
+}
+
+function buildChildrenNavRows(
+ sortingOrder: SidebarTreeSortingOrder,
+ childrenIds: string[],
+ depth: number,
+ map: Map
+) {
+ const rows = childrenIds.reduce((acc, childId) => {
+ const childRow = map.get(childId)
+ if (childRow == null) {
+ return acc
+ }
+
+ if (childRow.archived) {
+ return acc
+ }
+
+ acc.push({
+ ...childRow,
+ depth,
+ rows: buildChildrenNavRows(
+ sortingOrder,
+ childRow.children,
+ depth + 1,
+ map
+ ),
+ })
+
+ return acc
+ }, [] as (SidebarTreeChildRow & { lastUpdated: string })[])
+
+ switch (sortingOrder) {
+ case 'a-z':
+ return sortByAttributeAsc('label', rows)
+ case 'z-a':
+ return sortByAttributeDesc('label', rows)
+ case 'last-updated':
+ return sortByAttributeDesc('lastUpdated', rows)
+ case 'drag':
+ default:
+ return rows
+ }
+}
+
+type CloudTreeItem = {
+ id: string
+ parentId?: string
+ label: string
+ defaultIcon?: string
+ emoji?: string
+ bookmarked?: boolean
+ archived?: boolean
+ children: string[]
+ folding?: FoldingProps
+ folded?: boolean
+ href?: string
+ active?: boolean
+ lastUpdated: string
+ navigateTo?: () => void
+ controls?: SidebarNavControls[]
+ contextControls?: MenuItem[]
+ dropIn?: boolean
+ dropAround?: boolean
+ onDragStart?: () => void
+ onDrop?: (position?: SidebarDragState) => void
+ onDragEnd?: () => void
+}
diff --git a/src/cloud/lib/hooks/useCloudUpdater.ts b/src/cloud/lib/hooks/useCloudApi.ts
similarity index 99%
rename from src/cloud/lib/hooks/useCloudUpdater.ts
rename to src/cloud/lib/hooks/useCloudApi.ts
index 0037bee5f8..32907163b4 100644
--- a/src/cloud/lib/hooks/useCloudUpdater.ts
+++ b/src/cloud/lib/hooks/useCloudApi.ts
@@ -61,7 +61,7 @@ import useBulkApi from '../../../shared/lib/hooks/useBulkApi'
import { getMapFromEntityArray } from '../../../shared/lib/utils/array'
import { SerializedWorkspace } from '../../interfaces/db/workspace'
-export function useCloudUpdater() {
+export function useCloudApi() {
const { pageDoc, pageFolder, setPartialPageData } = usePage()
const {
updateWorkspacesMap,
diff --git a/src/cloud/lib/hooks/useCloudUI.tsx b/src/cloud/lib/hooks/useCloudResourceModals.tsx
similarity index 98%
rename from src/cloud/lib/hooks/useCloudUI.tsx
rename to src/cloud/lib/hooks/useCloudResourceModals.tsx
index e5b003692b..f0cba504dc 100644
--- a/src/cloud/lib/hooks/useCloudUI.tsx
+++ b/src/cloud/lib/hooks/useCloudResourceModals.tsx
@@ -10,9 +10,9 @@ import { SerializedDoc } from '../../interfaces/db/doc'
import { SerializedFolder } from '../../interfaces/db/folder'
import { SerializedTeam } from '../../interfaces/db/team'
import { SerializedWorkspace } from '../../interfaces/db/workspace'
-import { useCloudUpdater } from './useCloudUpdater'
+import { useCloudApi } from './useCloudApi'
-export function useCloudUI() {
+export function useCloudResourceModals() {
const { openModal, closeLastModal } = useModal()
const { messageBox } = useDialog()
const {
@@ -24,7 +24,7 @@ export function useCloudUI() {
deleteFolderApi,
deleteDocApi,
toggleDocArchive,
- } = useCloudUpdater()
+ } = useCloudApi()
const openWorkspaceEditForm = useCallback(
(wp: SerializedWorkspace) => {
diff --git a/src/cloud/lib/mappers/topbarBreadcrumbs.ts b/src/cloud/lib/mappers/topbarBreadcrumbs.ts
index 1fd5c2b74b..0a7660ae2d 100644
--- a/src/cloud/lib/mappers/topbarBreadcrumbs.ts
+++ b/src/cloud/lib/mappers/topbarBreadcrumbs.ts
@@ -20,7 +20,10 @@ import {
} from '../../interfaces/db/folder'
import { SerializedTeam } from '../../interfaces/db/team'
import { SerializedWorkspace } from '../../interfaces/db/workspace'
-import { CloudNewResourceRequestBody, UIFormOptions } from '../hooks/useCloudUI'
+import {
+ CloudNewResourceRequestBody,
+ UIFormOptions,
+} from '../hooks/useCloudResourceModals'
import { getDocTitle, prefixFolders } from '../utils/patterns'
import { getHexFromUUID } from '../utils/string'
import { topParentId } from './topbarTree'
From fb524ec080e589a518765b1f08af0681175133cc Mon Sep 17 00:00:00 2001
From: davy-c
Date: Fri, 21 May 2021 09:41:55 +0900
Subject: [PATCH 84/91] tmp
---
src/cloud/components/Application.tsx | 35 +++++++++++++++++--
.../Modal/contents/DiscountModal.tsx | 15 ++++++++
src/cloud/interfaces/analytics/mixpanel.ts | 2 ++
src/cloud/lib/subscription.ts | 15 ++++++++
4 files changed, 64 insertions(+), 3 deletions(-)
create mode 100644 src/cloud/components/organisms/Modal/contents/DiscountModal.tsx
diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx
index c45465e71e..ac78bed5e0 100644
--- a/src/cloud/components/Application.tsx
+++ b/src/cloud/components/Application.tsx
@@ -58,6 +58,7 @@ import {
mdiDownload,
mdiFileDocumentMultipleOutline,
mdiFileDocumentOutline,
+ mdiGiftOutline,
mdiLogoutVariant,
mdiMagnify,
mdiPlusCircleOutline,
@@ -87,6 +88,11 @@ import {
import { ModalOpeningOptions, useModal } from '../../shared/lib/stores/modal'
import NewDocButton from './molecules/NewDocButton'
import { useCloudSidebarTree } from '../lib/hooks/sidebar/useCloudSidebarTree'
+import { SerializedSubscription } from '../interfaces/db/subscription'
+import { isEligibleForDiscount } from '../lib/subscription'
+import { trackEvent } from '../api/track'
+import { MixpanelActionTrackTypes } from '../interfaces/analytics/mixpanel'
+import DiscountModal from './organisms/Modal/contents/DiscountModal'
interface ApplicationProps {
content: ContentLayoutProps
@@ -113,6 +119,7 @@ const Application = ({
permissions = [],
guestsMap,
currentUserPermissions,
+ subscription,
} = usePage()
const { openModal } = useModal()
const {
@@ -180,9 +187,18 @@ const Application = ({
openModal,
openSettingsTab,
sidebarState,
- team
+ team,
+ subscription
)
- }, [sidebarState, openModal, openSettingsTab, team, openState, showSpaces])
+ }, [
+ sidebarState,
+ openModal,
+ openSettingsTab,
+ team,
+ openState,
+ showSpaces,
+ subscription,
+ ])
const topbarTree = useMemo(() => {
if (team == null) {
@@ -617,7 +633,8 @@ function mapToolbarRows(
openModal: (cmp: JSX.Element, options?: ModalOpeningOptions) => void,
openSettingsTab: (tab: SettingsTab) => void,
sidebarState?: SidebarState,
- team?: SerializedTeam
+ team?: SerializedTeam,
+ subscription?: SerializedSubscription
) {
const rows: SidebarToolbarRow[] = []
if (team != null) {
@@ -652,6 +669,18 @@ function mapToolbarRows(
icon: mdiClockOutline,
onClick: () => openState('timeline'),
})
+
+ if (team != null && subscription == null && isEligibleForDiscount(team)) {
+ rows.push({
+ tooltip: 'New user discount~',
+ icon: mdiGiftOutline,
+ onClick: () => {
+ trackEvent(MixpanelActionTrackTypes.UpgradeDiscount, { team: team.id })
+ openModal( )
+ },
+ })
+ }
+
rows.push({
tooltip: 'Import',
icon: mdiDownload,
diff --git a/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx b/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx
new file mode 100644
index 0000000000..2f9265bed2
--- /dev/null
+++ b/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx
@@ -0,0 +1,15 @@
+import React from 'react'
+import styled from '../../../../../shared/lib/styled'
+import { SerializedTeam } from '../../../../interfaces/db/team'
+
+interface DiscountModalProps {
+ team: SerializedTeam
+}
+
+const DiscountModal = ({ team }: DiscountModalProps) => {
+ return discount there
+}
+
+const Container = styled.div``
+
+export default DiscountModal
diff --git a/src/cloud/interfaces/analytics/mixpanel.ts b/src/cloud/interfaces/analytics/mixpanel.ts
index fe23b821a2..515a1bb41f 100644
--- a/src/cloud/interfaces/analytics/mixpanel.ts
+++ b/src/cloud/interfaces/analytics/mixpanel.ts
@@ -72,6 +72,7 @@ export enum MixpanelActionTrackTypes {
UpgradeRevision = 'upgrade.origin.revision',
UpgradeGuest = 'upgrade.origin.guest',
UpgradeLimit = 'upgrade.origin.limit',
+ UpgradeDiscount = 'upgrade.origin.discount',
WorkspaceOpen = 'workspace.open',
WorkspaceCreate = 'workspace.create',
WorkspaceDelete = 'workspace.delete',
@@ -100,6 +101,7 @@ export type MixpanelFrontEvent =
| MixpanelActionTrackTypes.UpgradePassword
| MixpanelActionTrackTypes.UpgradeRevision
| MixpanelActionTrackTypes.DocFeatureRevision
+ | MixpanelActionTrackTypes.UpgradeDiscount
export type MixpanelUserEvent = MixpanelActionTrackTypes.AccountDelete
diff --git a/src/cloud/lib/subscription.ts b/src/cloud/lib/subscription.ts
index d1a4852229..6e8c282cfc 100644
--- a/src/cloud/lib/subscription.ts
+++ b/src/cloud/lib/subscription.ts
@@ -1,3 +1,6 @@
+import { differenceInDays } from 'date-fns'
+import { SerializedTeam } from '../interfaces/db/team'
+
export const freePlanDocLimit = 30
export const freeTrialPeriodDays = 7
export const guestsPerMember = 3
@@ -7,3 +10,15 @@ export const standardPlanStorageMb = 1000
export const proPlanStorageMb = 10000
export const revisionHistoryStandardDays = 7
+export const newTeamDiscountDays = 7
+
+export function isEligibleForDiscount(team: SerializedTeam) {
+ if (
+ differenceInDays(Date.now(), new Date(team.createdAt)) <=
+ newTeamDiscountDays
+ ) {
+ return true
+ }
+
+ return false
+}
From 6ed6f643762f92ebc66a9d189427fd4a50a75cf4 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Fri, 21 May 2021 12:34:34 +0900
Subject: [PATCH 85/91] tmp - plans renewal
---
package-lock.json | 8 +
package.json | 1 +
src/cloud/components/Application.tsx | 6 +-
.../Modal/contents/DiscountModal.tsx | 120 ++++++-
.../organisms/Subscription/PlanTables.tsx | 312 +-----------------
.../Sidebar/molecules/SidebarToolbar.tsx | 105 ++++--
6 files changed, 220 insertions(+), 332 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index e28b4ee180..0403b27441 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27631,6 +27631,14 @@
"tinycolor2": "^1.4.1"
}
},
+ "react-countdown": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/react-countdown/-/react-countdown-2.3.2.tgz",
+ "integrity": "sha512-Q4SADotHtgOxNWhDdvgupmKVL0pMB9DvoFcxv5AzjsxVhzOVxnttMbAywgqeOdruwEAmnPhOhNv/awAgkwru2w==",
+ "requires": {
+ "prop-types": "^15.7.2"
+ }
+ },
"react-datepicker": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-3.4.1.tgz",
diff --git a/package.json b/package.json
index f48005b1a6..3aef91af07 100644
--- a/package.json
+++ b/package.json
@@ -190,6 +190,7 @@
"react": "^16.9.0",
"react-bootstrap": "^1.4.3",
"react-color": "^2.19.3",
+ "react-countdown": "^2.3.2",
"react-datepicker": "^3.4.1",
"react-dom": "^16.9.0",
"react-google-login": "^5.2.2",
diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx
index ac78bed5e0..56dda677ec 100644
--- a/src/cloud/components/Application.tsx
+++ b/src/cloud/components/Application.tsx
@@ -150,6 +150,8 @@ const Application = ({
if (query.settings === 'upgrade') {
openSettingsTab('teamUpgrade')
}
+
+ openModal( )
})
useEffect(() => {
@@ -672,8 +674,10 @@ function mapToolbarRows(
if (team != null && subscription == null && isEligibleForDiscount(team)) {
rows.push({
- tooltip: 'New user discount~',
+ position: 'bottom',
+ tooltip: 'Get the new user discount!',
icon: mdiGiftOutline,
+ pelletVariant: 'danger',
onClick: () => {
trackEvent(MixpanelActionTrackTypes.UpgradeDiscount, { team: team.id })
openModal( )
diff --git a/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx b/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx
index 2f9265bed2..ab69b301d5 100644
--- a/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx
+++ b/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx
@@ -1,15 +1,131 @@
import React from 'react'
import styled from '../../../../../shared/lib/styled'
import { SerializedTeam } from '../../../../interfaces/db/team'
+import Countdown from 'react-countdown'
+import { newTeamDiscountDays } from '../../../../lib/subscription'
+import PlanTables from '../../Subscription/PlanTables'
interface DiscountModalProps {
team: SerializedTeam
}
const DiscountModal = ({ team }: DiscountModalProps) => {
- return discount there
+ const eligibilityEnd = new Date(team.createdAt)
+ eligibilityEnd.setDate(eligibilityEnd.getDate() + newTeamDiscountDays)
+
+ return (
+
+
+
+ Subscribe now to receive a three months discount!
+
+ Time remaining
+
+
+
+
+ )
+}
+
+const DiscountCountdown = ({
+ days,
+ hours,
+ minutes,
+ seconds,
+ completed,
+}: {
+ days: number
+ hours: number
+ minutes: number
+ seconds: number
+ completed: boolean
+}) => {
+ if (completed) {
+ return (
+
+ Your eligibility for a discount has expired
+
+ )
+ }
+
+ return (
+
+ )
}
-const Container = styled.div``
+const Container = styled.div`
+ .discount__modal__header {
+ text-align: center;
+ }
+
+ .discount__modal__title {
+ margin: 0;
+ font-size: ${({ theme }) => theme.sizes.fonts.l}px;
+ }
+
+ .discount__modal__header > * + .discount__modal__header > * {
+ margin-top: ${({ theme }) => theme.sizes.spaces.df}px;
+ }
+
+ .discount__modal__description {
+ margin: ${({ theme }) => theme.sizes.spaces.df}px 0;
+ text-transform: uppercase;
+ color: ${({ theme }) => theme.colors.text.subtle};
+ font-size: ${({ theme }) => theme.sizes.fonts.md};
+ }
+
+ .countdown {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: center;
+ align-items: top;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.df}px;
+ }
+
+ .countdown__column {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ flex: 0 0 auto;
+ }
+
+ .countdown__column + .countdown__column {
+ margin-left: ${({ theme }) => theme.sizes.spaces.df}px;
+ }
+
+ .countdown__number {
+ background: #000;
+ color: #fff;
+ width: 70px;
+ font-size: ${({ theme }) => theme.sizes.fonts.xl}px;
+ text-align: center;
+ padding: ${({ theme }) => theme.sizes.spaces.sm}px
+ ${({ theme }) => theme.sizes.spaces.df}px;
+ }
+
+ .countdown__description {
+ margin-top: ${({ theme }) => theme.sizes.spaces.xsm}px;
+ text-transform: uppercase;
+ font-size: ${({ theme }) => theme.sizes.fonts.sm}px;
+ color: ${({ theme }) => theme.colors.text.subtle};
+ }
+`
export default DiscountModal
diff --git a/src/cloud/components/organisms/Subscription/PlanTables.tsx b/src/cloud/components/organisms/Subscription/PlanTables.tsx
index fdec200a6d..fac8d8c6bf 100644
--- a/src/cloud/components/organisms/Subscription/PlanTables.tsx
+++ b/src/cloud/components/organisms/Subscription/PlanTables.tsx
@@ -4,7 +4,6 @@ import { useMediaQuery } from 'react-responsive'
import { SerializedSubscription } from '../../../interfaces/db/subscription'
import { SerializedTeam } from '../../../interfaces/db/team'
import { UpgradePlans } from '../../../lib/stripe'
-import styled from '../../../lib/styled'
import {
freePlanDocLimit,
freePlanStorageMb,
@@ -15,11 +14,13 @@ import {
import cc from 'classcat'
import Button from '../../../../shared/components/atoms/Button'
import Link from '../../../../shared/components/atoms/Link'
+import styled from '../../../../shared/lib/styled'
interface PlanTablesProps {
team: SerializedTeam
subscription?: SerializedSubscription
selectedPlan: UpgradePlans | 'free'
+ discounted?: boolean
onFreeCallback?: () => void
onStandardCallback?: () => void
onProCallback?: () => void
@@ -34,13 +35,11 @@ const PlanTables = ({
onStandardCallback,
onProCallback,
subscription,
+ discounted,
}: PlanTablesProps) => {
const isTabletOrMobile = useMediaQuery({ maxWidth: 1080 })
const freeTrialContent = useMemo(() => {
- if (team == null) {
- return null
- }
if (subscription != null) {
if (subscription.status !== 'trialing') {
return null
@@ -75,227 +74,13 @@ const PlanTables = ({
}, [subscription, team, onTrialCallback])
return (
-
-
-
-
-
-
- Free
-
-
$0
-
- per user
-
- per month
-
-
-
- {selectedPlan === 'free' ? (
-
- Current Plan
-
- ) : (
-
- Downgrade
-
- )}
-
-
-
- Standard
-
-
$3
-
- per user
-
- per month
-
-
- {selectedPlan === 'standard' ? (
-
- Current Plan
-
- ) : (
-
- {selectedPlan === 'free' ? 'Upgrade' : 'Downgrade'}
-
- )}
-
-
-
- Pro
-
-
$8
-
- per user
-
- per month
-
-
-
- {selectedPlan === 'pro' ? (
-
- Current Plan
-
- ) : (
-
- Upgrade
-
- )}
- {freeTrialContent}
-
-
-
-
-
- Members
-
- Unlimited
-
-
- Unlimited
-
-
- Unlimited
-
-
-
-
- Documents
-
- {freePlanDocLimit} per team
-
-
- Unlimited
-
-
- Unlimited
-
-
-
-
- Storage limit
-
- {freePlanStorageMb}MB per member
-
-
-
- {standardPlanStorageMb / 1000}GB per member
-
-
-
- {proPlanStorageMb / 1000}GB per member
-
-
-
-
- Integrations
-
- 2000+ integrations
-
-
- 2000+ integrations
-
-
- 2000+ integrations
-
-
-
-
- Collaborative workspace
-
- ✓
-
-
-
- ✓
-
-
-
-
- ✓
-
-
-
-
-
- Revision History
-
- ⤬
-
-
-
-
- Last {revisionHistoryStandardDays} days
-
-
-
-
-
- ✓
-
-
-
-
-
- Guest invite
-
- ⤬
-
-
- ⤬
-
-
-
- ✓
-
-
-
-
-
- Password/Expiration date for sharing
-
- ⤬
-
-
- ⤬
-
-
-
- ✓
-
-
-
-
-
- Priority support
-
- ⤬
-
-
- ⤬
-
-
-
- ✓
-
-
-
-
-
+
+
)
}
@@ -304,80 +89,17 @@ const Container = styled.div`
width: 100%;
overflow: auto;
- &.mobile__layout {
- border-spacing: 6px 0;
- }
-
- > table {
- margin-bottom: ${({ theme }) => theme.space.medium}px;
- table-layout: fixed;
- border-collapse: separate;
- border-spacing: 20px 0;
- min-width: 600px;
- }
-
- .first {
- width: 30%;
- }
-
- .header {
- vertical-align: top;
- }
-
- label {
- display: block;
- margin-bottom: ${({ theme }) => theme.space.small}px;
- font-size: ${({ theme }) => theme.fontSizes.xlarge}px;
- font-weight: 600;
- }
-
- .pricing {
+ .plans__header {
display: flex;
- align-items: center;
- margin-bottom: ${({ theme }) => theme.space.xsmall}px;
-
- span {
- font-size: ${({ theme }) => theme.fontSizes.xxlarge}px;
- margin-right: ${({ theme }) => theme.space.xsmall}px;
- }
- div {
- font-size: ${({ theme }) => theme.fontSizes.xsmall}px;
- line-height: 1;
- opacity: 0.6;
- width: 70px;
- padding-top: 2px;
- }
+ flex-direction: row;
+ flex-wrap: nowrap;
+ flex: 1 1 auto;
}
- .upgrade-btn {
+ &.plans--mobile .plans__header {
+ flex-wrap: wrap;
width: 100%;
- margin: ${({ theme }) => theme.fontSizes.xsmall}px 0;
- }
-
- tr td {
- padding-top: ${({ theme }) => theme.space.xsmall}px;
- padding-bottom: ${({ theme }) => theme.space.xsmall}px;
- border-bottom: 1px solid ${({ theme }) => theme.subtleBorderColor};
- text-align: left;
- min-height: 30px;
-
- &:not(.first):not(.header) {
- padding: ${({ theme }) => theme.space.xsmall}px;
- }
-
- &.first {
- color: ${({ theme }) => theme.subtleTextColor};
- }
- }
-
- .perk {
- line-height: 1.2;
- padding: 6px 0px;
- }
-
- .check {
- color: ${({ theme }) => theme.primaryTextColor};
- font-weight: bold;
+ flex: 0 0 auto;
}
`
diff --git a/src/shared/components/organisms/Sidebar/molecules/SidebarToolbar.tsx b/src/shared/components/organisms/Sidebar/molecules/SidebarToolbar.tsx
index 10728ae1e2..b9aa1ff175 100644
--- a/src/shared/components/organisms/Sidebar/molecules/SidebarToolbar.tsx
+++ b/src/shared/components/organisms/Sidebar/molecules/SidebarToolbar.tsx
@@ -11,6 +11,7 @@ export type SidebarToolbarRow = {
active?: boolean
tooltip?: string
position?: 'top' | 'bottom'
+ pelletVariant?: 'primary' | 'danger' | 'warning'
onClick?: () => void
}
@@ -49,44 +50,20 @@ const SidebarToolbar: AppComponent = ({
{sortedRows.top.map((row, i) => (
-
-
- {typeof row.icon === 'string' ? (
-
- ) : (
- row.icon
- )}
-
-
+
))}
{sortedRows.bottom.map((row, i) => (
-
-
- {typeof row.icon === 'string' ? (
-
- ) : (
- row.icon
- )}
-
-
+
))}
@@ -94,6 +71,40 @@ const SidebarToolbar: AppComponent = ({
)
}
+const SidebarToolbarItem = ({
+ row,
+ iconSize,
+}: {
+ row: SidebarToolbarRow
+ iconSize: IconSize
+}) => (
+
+
+ {row.pelletVariant != null && (
+
+ )}
+ {typeof row.icon === 'string' ? (
+
+ ) : (
+ row.icon
+ )}
+
+
+)
+
export default SidebarToolbar
const toolbarSpacing = 15
@@ -147,6 +158,7 @@ const Container = styled.div<{ iconSize: number }>`
margin: 0 0 ${toolbarSpacing}px 0;
position: relative;
justify-content: center;
+ position: relative;
&:hover,
&.sidebar__toolbar__item--active {
@@ -158,4 +170,29 @@ const Container = styled.div<{ iconSize: number }>`
}
}
}
+
+ .sidebar__toolbar__item__pellet {
+ position: absolute;
+ z-index: 1;
+ top: 2px;
+ right: 2px;
+ display: block;
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: ${({ theme }) => theme.colors.background.secondary};
+
+ &.sidebar__toolbar__item__pellet--danger {
+ background: ${({ theme }) => theme.colors.variants.danger.base};
+ filter: brightness(160%);
+ }
+
+ &.sidebar__toolbar__item__pellet--info {
+ background: ${({ theme }) => theme.colors.variants.info.base};
+ }
+
+ &.sidebar__toolbar__item__pellet--warning {
+ background: ${({ theme }) => theme.colors.variants.warning.base};
+ }
+ }
`
From b51d53eead9a0bd289ffcc69133c8540c2a3d792 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Sat, 22 May 2021 10:01:35 +0900
Subject: [PATCH 86/91] discount and upgrade tab
---
src/cloud/components/Application.tsx | 4 +-
.../Modal/contents/DiscountModal.tsx | 67 +++-
.../organisms/Subscription/PlanTables.tsx | 317 ++++++++++++++++--
.../organisms/settings/SettingsComponent.tsx | 13 +-
.../organisms/settings/TeamSubLimit.tsx | 31 +-
.../organisms/settings/UpgradeTab.tsx | 37 +-
src/cloud/lib/stores/settings/store.ts | 12 +-
src/cloud/lib/stripe.ts | 21 ++
src/shared/components/atoms/Banner.tsx | 56 ++++
src/shared/lib/styled/dark.ts | 2 +-
src/shared/lib/styled/light.ts | 2 +-
11 files changed, 516 insertions(+), 46 deletions(-)
create mode 100644 src/shared/components/atoms/Banner.tsx
diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx
index 56dda677ec..3cd34f95fa 100644
--- a/src/cloud/components/Application.tsx
+++ b/src/cloud/components/Application.tsx
@@ -150,8 +150,6 @@ const Application = ({
if (query.settings === 'upgrade') {
openSettingsTab('teamUpgrade')
}
-
- openModal( )
})
useEffect(() => {
@@ -680,7 +678,7 @@ function mapToolbarRows(
pelletVariant: 'danger',
onClick: () => {
trackEvent(MixpanelActionTrackTypes.UpgradeDiscount, { team: team.id })
- openModal( )
+ openModal( , { showCloseIcon: true, width: 'large' })
},
})
}
diff --git a/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx b/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx
index ab69b301d5..8cbf163666 100644
--- a/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx
+++ b/src/cloud/components/organisms/Modal/contents/DiscountModal.tsx
@@ -1,15 +1,34 @@
import React from 'react'
import styled from '../../../../../shared/lib/styled'
-import { SerializedTeam } from '../../../../interfaces/db/team'
import Countdown from 'react-countdown'
import { newTeamDiscountDays } from '../../../../lib/subscription'
import PlanTables from '../../Subscription/PlanTables'
+import { useSettings } from '../../../../lib/stores/settings'
+import { useModal } from '../../../../../shared/lib/stores/modal'
+import { usePage } from '../../../../lib/stores/pageStore'
+import Banner from '../../../../../shared/components/atoms/Banner'
+import { mdiExclamation } from '@mdi/js'
+import TeamSubLimit from '../../settings/TeamSubLimit'
-interface DiscountModalProps {
- team: SerializedTeam
-}
+const DiscountModal = () => {
+ const { openSettingsTab } = useSettings()
+ const { closeAllModals } = useModal()
+ const { team, subscription } = usePage()
+
+ if (team == null) {
+ return null
+ }
+
+ if (subscription != null) {
+ return (
+
+
+ You are already subscribed
+
+
+ )
+ }
-const DiscountModal = ({ team }: DiscountModalProps) => {
const eligibilityEnd = new Date(team.createdAt)
eligibilityEnd.setDate(eligibilityEnd.getDate() + newTeamDiscountDays)
@@ -21,7 +40,41 @@ const DiscountModal = ({ team }: DiscountModalProps) => {
Time remaining
-
+ {
+ openSettingsTab('teamUpgrade', {
+ initialPlan: 'standard',
+ tabState: 'form',
+ })
+ closeAllModals()
+ }}
+ />
+ }
+ onStandardCallback={() => {
+ openSettingsTab('teamUpgrade', {
+ initialPlan: 'standard',
+ tabState: 'form',
+ })
+ closeAllModals()
+ }}
+ onProCallback={() => {
+ openSettingsTab('teamUpgrade', {
+ initialPlan: 'pro',
+ tabState: 'form',
+ })
+ closeAllModals()
+ }}
+ onTrialCallback={() => {
+ openSettingsTab('teamUpgrade', { showTrialPopup: true })
+ closeAllModals()
+ }}
+ />
)
@@ -96,7 +149,7 @@ const Container = styled.div`
flex-wrap: nowrap;
justify-content: center;
align-items: top;
- margin-bottom: ${({ theme }) => theme.sizes.spaces.df}px;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.xl}px;
}
.countdown__column {
diff --git a/src/cloud/components/organisms/Subscription/PlanTables.tsx b/src/cloud/components/organisms/Subscription/PlanTables.tsx
index fac8d8c6bf..40bc450571 100644
--- a/src/cloud/components/organisms/Subscription/PlanTables.tsx
+++ b/src/cloud/components/organisms/Subscription/PlanTables.tsx
@@ -3,7 +3,12 @@ import React, { useMemo } from 'react'
import { useMediaQuery } from 'react-responsive'
import { SerializedSubscription } from '../../../interfaces/db/subscription'
import { SerializedTeam } from '../../../interfaces/db/team'
-import { UpgradePlans } from '../../../lib/stripe'
+import {
+ stripeProPlanUnit,
+ stripeStandardPlanUnit,
+ UpgradePlans,
+ discountPlans,
+} from '../../../lib/stripe'
import {
freePlanDocLimit,
freePlanStorageMb,
@@ -13,14 +18,15 @@ import {
} from '../../../lib/subscription'
import cc from 'classcat'
import Button from '../../../../shared/components/atoms/Button'
-import Link from '../../../../shared/components/atoms/Link'
import styled from '../../../../shared/lib/styled'
+import plur from 'plur'
interface PlanTablesProps {
team: SerializedTeam
subscription?: SerializedSubscription
selectedPlan: UpgradePlans | 'free'
discounted?: boolean
+ freePlanFooter?: React.ReactNode
onFreeCallback?: () => void
onStandardCallback?: () => void
onProCallback?: () => void
@@ -36,6 +42,7 @@ const PlanTables = ({
onProCallback,
subscription,
discounted,
+ freePlanFooter,
}: PlanTablesProps) => {
const isTabletOrMobile = useMediaQuery({ maxWidth: 1080 })
@@ -59,48 +66,314 @@ const PlanTables = ({
}
return (
-
- {
- e.preventDefault()
- onTrialCallback()
- }}
- >
- 7 days free trial
-
-
+ {
+ e.preventDefault()
+ onTrialCallback()
+ }}
+ >
+ 7 days free trial
+
)
}, [subscription, team, onTrialCallback])
return (
-
-
-
-
+
+
+
Free
+
+
$0
+
+ per member per month
+
+
+
+
+
+ Unlimited members
+
+
+ {freePlanDocLimit} docs per team
+
+
+ {freePlanStorageMb}MB per member
+
+
+
+ {selectedPlan === 'free' ? (
+ freePlanFooter != null ? (
+ freePlanFooter
+ ) : (
+
+ Current Plan
+
+ )
+ ) : (
+
+ Downgrade
+
+ )}
+
+
+
+
+
Standard
+
+
+ ${stripeStandardPlanUnit}
+
+ {discounted && (
+
+ ${stripeStandardPlanUnit - discountPlans.standard.amountOff}
+
+ )}
+
+ per member per month
+
+
+
+ {discounted && (
+
+ {discountPlans.standard.percentageOff}% OFF for{' '}
+ {discountPlans.standard.durationInMonths}{' '}
+ {plur('month', discountPlans.standard.durationInMonths)}
+
+ )}
+
+
+ Support development
+
+
+ Unlimited documents
+
+
+
+ Last {revisionHistoryStandardDays} days of your docs's
+ revision history
+
+
+
+ {standardPlanStorageMb / 1000}GB per member
+
+
+
+ {selectedPlan === 'standard' ? (
+
+ Current Plan
+
+ ) : (
+
+ {selectedPlan === 'free' ? 'Upgrade' : 'Downgrade'}
+
+ )}
+
+
+
+
+
Pro
+
+
+ ${stripeProPlanUnit}
+
+ {discounted && (
+
+ ${stripeProPlanUnit - discountPlans.pro.amountOff}
+
+ )}
+
+ per member per month
+
+
+
+ {discounted && (
+
+ {discountPlans.pro.percentageOff}% OFF for{' '}
+ {discountPlans.pro.durationInMonths}{' '}
+ {plur('month', discountPlans.pro.durationInMonths)}
+
+ )}
+
+
+ Guest invite
+
+
+ Password and expiration date when sharing
+
+
+ Full access to your docs's revision history
+
+
+ {proPlanStorageMb / 1000}GB per member
+
+
+
+ {selectedPlan === 'pro' ? (
+
+ Current Plan
+
+ ) : (
+
+ Upgrade
+
+ )}
+ {freeTrialContent}
)
}
+const footerPadding = 100
const Container = styled.div`
width: 100%;
overflow: auto;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ flex: 1 1 auto;
+
+ .plan__item__footer {
+ position: absolute;
+ bottom: 0;
+ height: ${footerPadding}px;
+ width: 100%;
+ left: 0;
+
+ .upgrade__btn,
+ .free__trial__btn {
+ width: 100%;
+ display: flex;
+ }
+
+ > * {
+ margin: 0;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
+ }
+ }
+
+ .plan__item__perks {
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
+ }
+
+ .plan__item__perk {
+ position: relative;
+ color: ${({ theme }) => theme.colors.text.secondary};
+ display: flex;
+ align-items: flex-start;
+
+ &::before {
+ content: '✓';
+ display: block;
+ color: ${({ theme }) => theme.colors.text.link};
+ font-size: ${({ theme }) => theme.sizes.fonts.l}px;
+ padding-right: ${({ theme }) => theme.sizes.spaces.sm}px;
+ line-height: ${({ theme }) => theme.sizes.fonts.df}px;
+ }
+ }
+
+ .plan__item__perk + .plan__item__perk {
+ margin-top: ${({ theme }) => theme.sizes.spaces.xsm}px;
+ }
+
+ .plan__item__discount {
+ font-size: ${({ theme }) => theme.sizes.fonts.md}px;
+ color: ${({ theme }) => theme.colors.variants.warning.base};
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
+ }
- .plans__header {
+ .plan__item__price {
display: flex;
- flex-direction: row;
- flex-wrap: nowrap;
- flex: 1 1 auto;
+ align-items: center;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
+ justify-content: flex-start;
+
+ &.plan__item__price--discounted {
+ .plan__item__price__default::after,
+ .plan__item__price__default::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ width: 100%;
+ height: 2px;
+ background: ${({ theme }) => theme.colors.text.primary};
+ }
+
+ .plan__item__price__default::after {
+ bottom: 35%;
+ }
+ .plan__item__price__default::before {
+ top: 35%;
+ }
+ }
+
+ .plan__item__price__default,
+ .plan__item__price__discount {
+ position: relative;
+ font-size: ${({ theme }) => theme.sizes.fonts.xl}px;
+ margin-right: ${({ theme }) => theme.sizes.spaces.sm}px;
+ }
+
+ .plan__item__price__discount {
+ color: ${({ theme }) => theme.colors.variants.warning.base};
+ }
+
+ .plan__item__price__description {
+ font-size: ${({ theme }) => theme.sizes.fonts.xsm}px;
+ line-height: 1;
+ opacity: 0.6;
+ width: 70px;
+ padding-top: 2px;
+ }
}
- &.plans--mobile .plans__header {
+ .plan__item__title {
+ display: block;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px;
+ font-size: ${({ theme }) => theme.sizes.fonts.l}px;
+ font-weight: 600;
+ }
+
+ &.plans--mobile {
flex-wrap: wrap;
width: 100%;
flex: 0 0 auto;
}
+
+ .plan__item {
+ text-align: left;
+ width: 29%;
+ margin: 0 2%;
+ padding-bottom: ${footerPadding}px;
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ }
`
export default PlanTables
diff --git a/src/cloud/components/organisms/settings/SettingsComponent.tsx b/src/cloud/components/organisms/settings/SettingsComponent.tsx
index 975df105fd..13686ba341 100644
--- a/src/cloud/components/organisms/settings/SettingsComponent.tsx
+++ b/src/cloud/components/organisms/settings/SettingsComponent.tsx
@@ -42,10 +42,15 @@ import { intercomAppId } from '../../../lib/consts'
const SettingsComponent = () => {
const { t } = useTranslation()
- const { closed, toggleClosed, settingsTab } = useSettings()
+ const {
+ closed,
+ toggleClosed,
+ settingsTab,
+ openSettingsTab,
+ settingsOpeningOptions,
+ } = useSettings()
const contentSideRef = React.createRef
()
const menuRef = React.createRef()
- const { openSettingsTab } = useSettings()
const { team, subscription, currentUserPermissions } = usePage<
PageStoreWithTeam
>()
@@ -101,7 +106,7 @@ const SettingsComponent = () => {
case 'teamMembers':
return
case 'teamUpgrade':
- return
+ return
case 'teamSubscription':
return
case 'integrations':
@@ -119,7 +124,7 @@ const SettingsComponent = () => {
default:
return
}
- }, [settingsTab, currentUserPermissions])
+ }, [settingsTab, currentUserPermissions, settingsOpeningOptions])
useEffect(() => {
if (closed) {
diff --git a/src/cloud/components/organisms/settings/TeamSubLimit.tsx b/src/cloud/components/organisms/settings/TeamSubLimit.tsx
index 8ddaa5b167..126987b56e 100644
--- a/src/cloud/components/organisms/settings/TeamSubLimit.tsx
+++ b/src/cloud/components/organisms/settings/TeamSubLimit.tsx
@@ -4,7 +4,13 @@ import { usePage } from '../../../lib/stores/pageStore'
import { useSettings } from '../../../lib/stores/settings'
import styled from '../../../../shared/lib/styled'
-const TeamSubLimit = () => {
+const TeamSubLimit = ({
+ padded = true,
+ onLimitClick,
+}: {
+ padded?: boolean
+ onLimitClick?: () => void
+}) => {
const { subscription, team, currentSubInfo } = usePage()
const { openSettingsTab } = useSettings()
@@ -18,12 +24,18 @@ const TeamSubLimit = () => {
if (currentSubInfo.trialing) {
return (
-
+
{
e.preventDefault()
+ if (onLimitClick != null) {
+ onLimitClick()
+ return
+ }
openSettingsTab('teamUpgrade')
}}
>
@@ -41,12 +53,18 @@ const TeamSubLimit = () => {
}
return (
-
+
{
e.preventDefault()
+ if (onLimitClick != null) {
+ onLimitClick()
+ return
+ }
openSettingsTab('teamUpgrade')
}}
>
@@ -77,6 +95,13 @@ const Container = styled.nav`
width: 100%;
margin-top: ${({ theme }) => theme.sizes.spaces.l}px;
+ &.sub__limit--stripped {
+ margin: 0;
+ > * {
+ margin: 0 !important;
+ }
+ }
+
h6 {
margin: 0;
color: ${({ theme }) => theme.colors.variants.primary.base};
diff --git a/src/cloud/components/organisms/settings/UpgradeTab.tsx b/src/cloud/components/organisms/settings/UpgradeTab.tsx
index a9e5098ef1..8fc4dab922 100644
--- a/src/cloud/components/organisms/settings/UpgradeTab.tsx
+++ b/src/cloud/components/organisms/settings/UpgradeTab.tsx
@@ -16,12 +16,29 @@ import { UpgradePlans } from '../../../lib/stripe'
import styled from '../../../lib/styled'
import SettingTabContent from '../../../../shared/components/organisms/Settings/atoms/SettingTabContent'
import { ExternalLink } from '../../../../shared/components/atoms/Link'
+import {
+ isEligibleForDiscount,
+ newTeamDiscountDays,
+} from '../../../lib/subscription'
+import Banner from '../../../../shared/components/atoms/Banner'
+import { mdiGift } from '@mdi/js'
+import { format } from 'date-fns'
const stripePromise = loadStripe(stripePublishableKey)
type UpgradeTabs = 'plans' | 'form'
-const UpgradeTab = () => {
+export interface UpgradeTabOpeningOptions {
+ tabState?: UpgradeTabs
+ showTrialPopup?: boolean
+ initialPlan?: UpgradePlans
+}
+
+const UpgradeTab = ({
+ tabState: defaultTabState = 'plans',
+ showTrialPopup: defaultShowTrial = false,
+ initialPlan: defaultInitialPlan = 'standard',
+}: UpgradeTabOpeningOptions) => {
const { t } = useTranslation()
const {
team,
@@ -29,13 +46,15 @@ const UpgradeTab = () => {
updateTeamSubscription,
permissions = [],
} = usePage()
- const [tabState, setTabState] = useState('plans')
+ const [tabState, setTabState] = useState(defaultTabState)
const { openSettingsTab } = useSettings()
const {
globalData: { currentUser },
} = useGlobalData()
- const [showTrialPopup, setShowTrialPopup] = useState(false)
- const [initialPlan, setInitialPlan] = useState('standard')
+ const [showTrialPopup, setShowTrialPopup] = useState(defaultShowTrial)
+ const [initialPlan, setInitialPlan] = useState(
+ defaultInitialPlan
+ )
useEffect(() => {
if (subscription != null && subscription.status !== 'trialing') {
@@ -73,6 +92,9 @@ const UpgradeTab = () => {
return null
}
+ const eligibilityEnd = new Date(team.createdAt)
+ eligibilityEnd.setDate(eligibilityEnd.getDate() + newTeamDiscountDays)
+ const teamIsEligibleForDiscount = isEligibleForDiscount(team)
if (tabState === 'plans') {
return (
{
/>
)}
+ {teamIsEligibleForDiscount && (
+
+ You will receive a discount as long as you subscribe before{' '}
+ {format(eligibilityEnd, 'H:m, dd MMM yyyy')}
+
+ )}
{
onStandardCallback={() => onUpgradeCallback('standard')}
onProCallback={() => onUpgradeCallback('pro')}
onTrialCallback={() => setShowTrialPopup(true)}
+ discounted={teamIsEligibleForDiscount}
/>
* For larger businesses or those in highly regulated industries,
diff --git a/src/cloud/lib/stores/settings/store.ts b/src/cloud/lib/stores/settings/store.ts
index 38f542fdc2..571165314e 100644
--- a/src/cloud/lib/stores/settings/store.ts
+++ b/src/cloud/lib/stores/settings/store.ts
@@ -10,6 +10,7 @@ import {
toggleSettingsMembersEventEmitter,
} from '../../utils/events'
import { useToast } from '../../../../shared/lib/stores/toast'
+import { UpgradeTabOpeningOptions } from '../../../components/organisms/settings/UpgradeTab'
export const baseUserSettings: UserSettings = {
'general.theme': 'dark',
@@ -32,10 +33,16 @@ export type SettingsTab =
| 'api'
| 'feedback'
+export type SettingsTabOpeningOptions = UpgradeTabOpeningOptions
+
function useSettingsStore() {
const { globalData, setPartialGlobalData } = useGlobalData()
const { currentUserSettings, currentUser } = globalData
const [settingsTab, setSettingsTab] = useState('personalInfo')
+ const [settingsOpeningOptions, setSettingsOpeningOptions] = useState<
+ SettingsTabOpeningOptions
+ >()
+
const { pushMessage } = useToast()
const { t } = useTranslation()
@@ -94,6 +101,7 @@ function useSettingsStore() {
const closeSettingsTab = useCallback(() => {
setClosed(true)
+ setSettingsOpeningOptions(undefined)
}, [setClosed])
const currentLanguage = mergedUserSettings['general.language']
@@ -103,8 +111,9 @@ function useSettingsStore() {
}, [i18n, currentLanguage])
const openSettingsTab = useCallback(
- (tab: SettingsTab) => {
+ (tab: SettingsTab, options?: SettingsTabOpeningOptions) => {
setClosed(false)
+ setSettingsOpeningOptions(options)
setSettingsTab(tab)
return
},
@@ -155,6 +164,7 @@ function useSettingsStore() {
settings: mergedUserSettings,
setSettings,
settingsTab,
+ settingsOpeningOptions,
openSettingsTab,
closeSettingsTab,
emailNotifications,
diff --git a/src/cloud/lib/stripe.ts b/src/cloud/lib/stripe.ts
index a0dd1af6a9..68ae436357 100644
--- a/src/cloud/lib/stripe.ts
+++ b/src/cloud/lib/stripe.ts
@@ -4,3 +4,24 @@ export const stripeStandardPlanUnit = 3
export const stripeStandardJpyPlanUnit = 300
export type UpgradePlans = 'standard' | 'pro'
+
+type DiscountParameters = {
+ durationInMonths: number
+ amountOff: number
+ percentageOff: number
+}
+
+type Discounts = Record
+
+export const discountPlans: Discounts = {
+ standard: {
+ durationInMonths: 3,
+ amountOff: 1,
+ percentageOff: 33,
+ },
+ pro: {
+ durationInMonths: 3,
+ amountOff: 4,
+ percentageOff: 50,
+ },
+}
diff --git a/src/shared/components/atoms/Banner.tsx b/src/shared/components/atoms/Banner.tsx
new file mode 100644
index 0000000000..7a11ce9339
--- /dev/null
+++ b/src/shared/components/atoms/Banner.tsx
@@ -0,0 +1,56 @@
+import React from 'react'
+import { AppComponent } from '../../lib/types'
+import Icon from './Icon'
+import cc from 'classcat'
+import styled from '../../lib/styled'
+
+interface BannerProps {
+ variant: 'danger' | 'warning' | 'info'
+ iconPath?: string
+}
+
+const Banner: AppComponent = ({
+ variant,
+ iconPath,
+ children,
+ className,
+}) => (
+
+ {iconPath != null && (
+
+ )}
+ {children}
+
+)
+
+const Container = styled.div`
+ display: flex;
+ width: 100%;
+ flex: 1 1 auto;
+ overflow: hidden;
+ white-space: none;
+ padding: ${({ theme }) => theme.sizes.spaces.df}px
+ ${({ theme }) => theme.sizes.spaces.md}px;
+ margin-bottom: ${({ theme }) => theme.sizes.spaces.md}px;
+
+ .banner__icon {
+ margin-right: ${({ theme }) => theme.sizes.spaces.sm}px;
+ }
+
+ &.banner--danger {
+ background-color: ${({ theme }) => theme.colors.variants.danger.base};
+ color: ${({ theme }) => theme.colors.variants.danger.text};
+ }
+
+ &.banner--warning {
+ background-color: ${({ theme }) => theme.colors.variants.warning.base};
+ color: ${({ theme }) => theme.colors.variants.warning.text};
+ }
+
+ &.banner--info {
+ background-color: ${({ theme }) => theme.colors.variants.info.base};
+ color: ${({ theme }) => theme.colors.variants.info.text};
+ }
+`
+
+export default Banner
diff --git a/src/shared/lib/styled/dark.ts b/src/shared/lib/styled/dark.ts
index dc1cf714f7..ab277b0b55 100644
--- a/src/shared/lib/styled/dark.ts
+++ b/src/shared/lib/styled/dark.ts
@@ -41,7 +41,7 @@ export const darkTheme: BaseTheme = {
},
warning: {
base: '#FFBB33',
- text: '#fff',
+ text: '#000',
},
success: {
base: '#00C851',
diff --git a/src/shared/lib/styled/light.ts b/src/shared/lib/styled/light.ts
index a66dd14563..cc261bdf1e 100644
--- a/src/shared/lib/styled/light.ts
+++ b/src/shared/lib/styled/light.ts
@@ -41,7 +41,7 @@ export const lightTheme: BaseTheme = {
},
warning: {
base: '#FFBB33',
- text: '#fff',
+ text: '#000',
},
success: {
base: '#00C851',
From 58b2b4b963e0048696937b059f963b3510e75c73 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Mon, 24 May 2021 09:47:56 +0900
Subject: [PATCH 87/91] front end
---
.../UpdateBillingEmailForm.tsx | 59 +++-
.../UpdateBillingMethodForm.tsx | 87 +++--
.../SubscriptionForm/UpdateBillingPromo.tsx | 48 ++-
.../molecules/SubscriptionForm/index.tsx | 328 ++++++------------
.../organisms/Subscription/PlanTables.tsx | 20 +-
.../Subscription/SubscriptionCostSummary.tsx | 155 +++++++++
.../Subscription/SubscriptionManagement.tsx | 285 ++++++---------
.../organisms/settings/SubscriptionTab.tsx | 1 -
.../organisms/settings/UpgradeTab.tsx | 56 +--
src/cloud/interfaces/db/subscription.ts | 1 +
src/cloud/interfaces/db/team.ts | 1 +
src/cloud/lib/stripe.ts | 2 +-
src/shared/components/atoms/Button.tsx | 2 +-
src/shared/components/atoms/Link.tsx | 2 +-
.../molecules/Form/atoms/FormStripeInput.tsx | 72 ++++
.../molecules/Form/templates/FormRow.tsx | 76 ++--
16 files changed, 633 insertions(+), 562 deletions(-)
create mode 100644 src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx
create mode 100644 src/shared/components/molecules/Form/atoms/FormStripeInput.tsx
diff --git a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx
index 79a2e439cf..e4c62f5225 100644
--- a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx
@@ -4,13 +4,15 @@ import {
SectionFlexRow,
} from '../../organisms/settings/styled'
import { SerializedSubscription } from '../../../interfaces/db/subscription'
-import { StyledBillingInput } from '.'
import { updateSubEmail } from '../../../api/teams/subscription/update'
import { useToast } from '../../../../shared/lib/stores/toast'
import Button, {
LoadingButton,
} from '../../../../shared/components/atoms/Button'
import ButtonGroup from '../../../../shared/components/atoms/ButtonGroup'
+import FormRow from '../../../../shared/components/molecules/Form/templates/FormRow'
+import Form from '../../../../shared/components/molecules/Form'
+import styled from '../../../../shared/lib/styled'
interface UpdateBillingEmailFormProps {
sub?: SerializedSubscription
@@ -64,28 +66,41 @@ const UpdateBillingEmailForm = ({
}
return (
-
-
- Update your billing email
-
- Current Email
- {sub.email}
-
+
+ Update your billing email
+
+ Current Email
+ {sub.email}
+
-
+
-
-
+
Cancel
-
-
+
+
)
}
+const Container = styled.div`
+ width: 100%;
+
+ .button__group {
+ margin-top: ${({ theme }) => theme.sizes.spaces.md}px;
+ }
+`
+
export default UpdateBillingEmailForm
diff --git a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingMethodForm.tsx b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingMethodForm.tsx
index fe2aaa26dd..c000bf1c89 100644
--- a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingMethodForm.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingMethodForm.tsx
@@ -6,19 +6,18 @@ import {
import { SerializedSubscription } from '../../../interfaces/db/subscription'
import { updateSubMethod } from '../../../api/teams/subscription/update'
import { useElements, useStripe, CardElement } from '@stripe/react-stripe-js'
-import {
- StripeElementStyle,
- StripeCardElementChangeEvent,
-} from '@stripe/stripe-js'
-import { selectTheme } from '../../../lib/styled'
+import { StripeCardElementChangeEvent } from '@stripe/stripe-js'
import { useSettings } from '../../../lib/stores/settings'
-import { StyledCardElementContainer } from './index'
import Alert from '../../../../components/atoms/Alert'
import { useToast } from '../../../../shared/lib/stores/toast'
import ButtonGroup from '../../../../shared/components/atoms/ButtonGroup'
import Button, {
LoadingButton,
} from '../../../../shared/components/atoms/Button'
+import FormStripeInput from '../../../../shared/components/molecules/Form/atoms/FormStripeInput'
+import FormRow from '../../../../shared/components/molecules/Form/templates/FormRow'
+import Form from '../../../../shared/components/molecules/Form'
+import styled from '../../../../shared/lib/styled'
interface UpdateBillingMethodFormProps {
sub?: SerializedSubscription
@@ -69,20 +68,6 @@ const UpdateBillingMethodForm = ({
}
}
- const stripeFormStyle: StripeElementStyle = useMemo(() => {
- const theme = selectTheme(settings['general.theme'])
- return {
- base: {
- color: theme.emphasizedTextColor,
- fontFamily: theme.fontFamily,
- fontSize: `${theme.fontSizes.default}px`,
- '::placeholder': {
- color: theme.subtleTextColor,
- },
- },
- }
- }, [settings])
-
const currentCardBrand = sub?.cardBrand
const [newCardBrand, setNewCardBrand] = useState('unknown')
@@ -124,7 +109,7 @@ const UpdateBillingMethodForm = ({
}
return (
-
+
Update your Credit Card
@@ -142,32 +127,46 @@ const UpdateBillingMethodForm = ({
)}
-
-
-
-
-
-
- Cancel
-
-
-
+
+
+
+
+
- Update
-
-
+
+ Cancel
+
+
+
+ Update
+
+
+
-
+
)
}
+const Container = styled.div`
+ width: 100%;
+
+ .button__group {
+ margin-top: ${({ theme }) => theme.sizes.spaces.md}px;
+ }
+`
+
export default UpdateBillingMethodForm
diff --git a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx
index 9a9c503d1f..af012fa2c9 100644
--- a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx
@@ -1,13 +1,15 @@
import React, { useState, useCallback } from 'react'
import { SectionIntroduction } from '../../organisms/settings/styled'
import { SerializedSubscription } from '../../../interfaces/db/subscription'
-import { StyledBillingInput } from '.'
import { redeemPromo } from '../../../api/teams/subscription'
import { useToast } from '../../../../shared/lib/stores/toast'
import Button, {
LoadingButton,
} from '../../../../shared/components/atoms/Button'
import ButtonGroup from '../../../../shared/components/atoms/ButtonGroup'
+import Form from '../../../../shared/components/molecules/Form'
+import FormRow from '../../../../shared/components/molecules/Form/templates/FormRow'
+import styled from '../../../../shared/lib/styled'
interface UpdateBillingPromoFormProps {
sub?: SerializedSubscription
@@ -76,17 +78,31 @@ const UpdateBillingPromoForm = ({
}
return (
-
-
- Apply a promotion code
-
+ Apply a promotion code
+
+
-
+
Cancel
@@ -100,9 +116,17 @@ const UpdateBillingPromoForm = ({
Apply
-
-
+
+
)
}
+const Container = styled.div`
+ width: 100%;
+
+ .button__group {
+ margin-top: ${({ theme }) => theme.sizes.spaces.md}px;
+ }
+`
+
export default UpdateBillingPromoForm
diff --git a/src/cloud/components/molecules/SubscriptionForm/index.tsx b/src/cloud/components/molecules/SubscriptionForm/index.tsx
index edaf8f35d2..beaff36086 100644
--- a/src/cloud/components/molecules/SubscriptionForm/index.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/index.tsx
@@ -3,28 +3,23 @@ import { useStripe, useElements, CardElement } from '@stripe/react-stripe-js'
import { createSubscription } from '../../../api/teams/subscription'
import { SerializedTeam } from '../../../interfaces/db/team'
import { SerializedSubscription } from '../../../interfaces/db/subscription'
-import { inputStyle } from '../../../lib/styled/styleFunctions'
-import styled from '../../../lib/styled'
-import Stripe, { StripeElementStyle } from '@stripe/stripe-js'
+import Stripe from '@stripe/stripe-js'
import { useSettings } from '../../../lib/stores/settings'
-import { selectTheme } from '../../../lib/styled'
import { usePage } from '../../../lib/stores/pageStore'
-import {
- stripeProPlanUnit,
- stripeStandardPlanUnit,
- UpgradePlans,
- stripeProJpyPlanUnit,
- stripeStandardJpyPlanUnit,
-} from '../../../lib/stripe'
-import plur from 'plur'
-import Icon from '../../../../components/atoms/Icon'
-import { mdiChevronDown, mdiChevronRight } from '@mdi/js'
+import { UpgradePlans } from '../../../lib/stripe'
import Alert from '../../../../components/atoms/Alert'
import { useToast } from '../../../../shared/lib/stores/toast'
import Button, {
LoadingButton,
} from '../../../../shared/components/atoms/Button'
import ButtonGroup from '../../../../shared/components/atoms/ButtonGroup'
+import SubscriptionCostSummary from '../../organisms/Subscription/SubscriptionCostSummary'
+import { isEligibleForDiscount } from '../../../lib/subscription'
+import FormRow from '../../../../shared/components/molecules/Form/templates/FormRow'
+import Form from '../../../../shared/components/molecules/Form'
+import styled from '../../../../shared/lib/styled'
+import FormStripeInput from '../../../../shared/components/molecules/Form/atoms/FormStripeInput'
+import { mdiChevronDown, mdiChevronRight } from '@mdi/js'
interface SubscriptionFormProps {
team: SerializedTeam
@@ -126,20 +121,6 @@ const SubscriptionForm = ({
}
}
- const stripeFormStyle: StripeElementStyle = useMemo(() => {
- const theme = selectTheme(settings['general.theme'])
- return {
- base: {
- color: theme.emphasizedTextColor,
- fontFamily: theme.fontFamily,
- fontSize: `${theme.fontSizes.default}px`,
- '::placeholder': {
- color: theme.subtleTextColor,
- },
- },
- }
- }, [settings])
-
const [newCardBrand, setNewCardBrand] = useState('unknown')
const handleCardElementChange = useCallback(
@@ -153,224 +134,117 @@ const SubscriptionForm = ({
return newCardBrand.toLowerCase() === 'jcb'
}, [newCardBrand])
- const unitPrice = useMemo(() => {
- if (currentPlan === 'pro') {
- if (usingJpyPricing) {
- return `¥${stripeProJpyPlanUnit}`
- }
- return `$${stripeProPlanUnit}`
- }
- if (usingJpyPricing) {
- return `¥${stripeStandardJpyPlanUnit}`
- }
- return `$${stripeStandardPlanUnit}`
- }, [currentPlan, usingJpyPricing])
-
const numberOfMembers = permissions.length
- const totalMonthlyPrice = useMemo(() => {
- if (currentPlan === 'pro') {
- if (usingJpyPricing) {
- return `¥${stripeProJpyPlanUnit * numberOfMembers}`
- }
- return `$${stripeProPlanUnit * numberOfMembers}`
- }
- if (usingJpyPricing) {
- return `¥${stripeStandardJpyPlanUnit * numberOfMembers}`
- }
- return `$${stripeStandardPlanUnit * numberOfMembers}`
- }, [currentPlan, usingJpyPricing, numberOfMembers])
-
return (
-
-
-
-
-
- {currentPlan === 'pro' ? 'Pro' : 'Standard'}
- {' '}
- {unitPrice} × {permissions.length}{' '}
- {plur('member', permissions.length)} × 1 month
-
-
-
- Total Monthly Price
- {totalMonthlyPrice}
-
-
- {usingJpyPricing && (
-
- We can only accept JPY(Japanese Yen) when paying by JCB cards.
-
- )}
- Payment Method
-
-
+
+
-
-
- {ongoingTrial != null && Your free trial will be stopped.
}
- {
- setShowPromoCode((prev) => !prev)
- }}
- disabled={sending}
- >
-
- Apply a coupon
-
- {showPromoCode && (
-
+ We can only accept JPY(Japanese Yen) when paying by JCB cards.
+
+ )}
+ Payment Method
+
+
+
+
- )}
-
- {onCancel != null && (
+
{
+ setShowPromoCode((prev) => !prev)
+ }}
disabled={sending}
- onClick={onCancel}
- variant='secondary'
>
- Cancel
+ Apply a coupon
+
+
+ {showPromoCode && (
+
)}
-
- Subscribe
-
-
-
+
+ {onCancel != null && (
+
+ Cancel
+
+ )}
+
+ Subscribe
+
+
+
+
)
}
export default SubscriptionForm
-export const StyledUpgradePlan = styled.div`
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: ${({ theme }) => theme.space.small}px 0;
- border: dashed ${({ theme }) => theme.subtleBorderColor};
- border-width: 1px 0;
-`
-
-export const StyledCalcuration = styled.div`
- .plan-name {
- display: inline-block;
- margin-right: ${({ theme }) => theme.space.xsmall}px;
- padding: 2px ${({ theme }) => theme.space.xxsmall}px;
- background-color: ${({ theme }) => theme.infoBackgroundColor};
- border-radius: 3px;
- color: ${({ theme }) => theme.whiteTextColor};
- font-size: ${({ theme }) => theme.fontSizes.xsmall}px;
- }
-`
-
export const StyledPaymentHeader = styled.h3`
- margin: ${({ theme }) => theme.space.large}px 0
- ${({ theme }) => theme.space.default}px;
- font-size: ${({ theme }) => theme.fontSizes.medium}px;
-`
-
-export const StyledTotal = styled.div`
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: ${({ theme }) => theme.space.small}px 0;
- border-bottom: 2px solid ${({ theme }) => theme.subtleBorderColor};
- font-size: ${({ theme }) => theme.fontSizes.large}px;
-
- label {
- margin: 0;
- font-weight: bold;
- }
+ margin: ${({ theme }) => theme.sizes.spaces.l}px 0
+ ${({ theme }) => theme.sizes.spaces.df}px;
+ font-size: ${({ theme }) => theme.sizes.fonts.md}px;
`
-export const StyledBillingInput = styled.input`
- ${inputStyle}
- flex-grow: 1;
- flex-shrink: 1;
- width: 100%;
- height: 40px;
- margin: ${({ theme }) => theme.space.default}px 0;
- padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.small}px;
- border-radius: 2px;
-`
-
-export const StyledBillingSeatsInput = styled.input`
- ${inputStyle}
- flex-grow: 0;
- flex-shrink: 0;
- text-align: right;
- width: 100px;
- height: 40px;
- padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.small}px;
- border-radius: 2px;
-`
-
-export const StyledSubscriptionForm = styled.form`
- width: 540px;
- margin-top: ${({ theme }) => theme.space.default}px;
-
- .btn-primary,
- .btn-secondary {
- margin-bottom: ${({ theme }) => theme.space.default}px;
- }
-
- .StripeElement {
- margin-top: 2px;
- }
-
- .sub__coupon {
- display: inline-flex;
- align-items: center;
- transition: 200ms color;
- background: none;
- border: none;
- outline: none;
- padding: 0;
- color: ${({ theme }) => theme.primaryTextColor};
- margin-bottom: ${({ theme }) => theme.space.xxsmall}px;
-
- &:hover,
- &:focus,
- &:active {
- text-decoration: underline;
- }
-
- svg {
- margin-left: ${({ theme }) => theme.space.xxsmall}px;
- }
- }
-
+export const Container = styled.div`
.button__group {
margin-top: 40px;
}
`
-
-export const StyledCardElementContainer = styled.div`
- ${inputStyle}
- height: 40px;
- padding: ${({ theme }) => theme.space.xsmall}px
- ${({ theme }) => theme.space.small}px;
- border-radius: 2px;
-`
diff --git a/src/cloud/components/organisms/Subscription/PlanTables.tsx b/src/cloud/components/organisms/Subscription/PlanTables.tsx
index 40bc450571..8dcd8b20f7 100644
--- a/src/cloud/components/organisms/Subscription/PlanTables.tsx
+++ b/src/cloud/components/organisms/Subscription/PlanTables.tsx
@@ -7,7 +7,7 @@ import {
stripeProPlanUnit,
stripeStandardPlanUnit,
UpgradePlans,
- discountPlans,
+ newUserDiscountPlans,
} from '../../../lib/stripe'
import {
freePlanDocLimit,
@@ -136,7 +136,9 @@ const PlanTables = ({
{discounted && (
- ${stripeStandardPlanUnit - discountPlans.standard.amountOff}
+ $
+ {stripeStandardPlanUnit -
+ newUserDiscountPlans.standard.amountOff}
)}
@@ -146,9 +148,9 @@ const PlanTables = ({
{discounted && (
- {discountPlans.standard.percentageOff}% OFF for{' '}
- {discountPlans.standard.durationInMonths}{' '}
- {plur('month', discountPlans.standard.durationInMonths)}
+ {newUserDiscountPlans.standard.percentageOff}% OFF for{' '}
+ {newUserDiscountPlans.standard.durationInMonths}{' '}
+ {plur('month', newUserDiscountPlans.standard.durationInMonths)}
)}
@@ -198,7 +200,7 @@ const PlanTables = ({
{discounted && (
- ${stripeProPlanUnit - discountPlans.pro.amountOff}
+ ${stripeProPlanUnit - newUserDiscountPlans.pro.amountOff}
)}
@@ -208,9 +210,9 @@ const PlanTables = ({
{discounted && (
- {discountPlans.pro.percentageOff}% OFF for{' '}
- {discountPlans.pro.durationInMonths}{' '}
- {plur('month', discountPlans.pro.durationInMonths)}
+ {newUserDiscountPlans.pro.percentageOff}% OFF for{' '}
+ {newUserDiscountPlans.pro.durationInMonths}{' '}
+ {plur('month', newUserDiscountPlans.pro.durationInMonths)}
)}
diff --git a/src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx b/src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx
new file mode 100644
index 0000000000..c0da4ab88f
--- /dev/null
+++ b/src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx
@@ -0,0 +1,155 @@
+import React, { useMemo } from 'react'
+import styled from '../../../../shared/lib/styled'
+import cc from 'classcat'
+import { AppComponent } from '../../../../shared/lib/types'
+import plur from 'plur'
+import {
+ stripeProJpyPlanUnit,
+ stripeProPlanUnit,
+ stripeStandardJpyPlanUnit,
+ stripeStandardPlanUnit,
+ UpgradePlans,
+ newUserDiscountPlans,
+} from '../../../lib/stripe'
+import Icon from '../../../../shared/components/atoms/Icon'
+import { mdiGiftOutline } from '@mdi/js'
+
+interface SubscriptionCostSummaryProps {
+ plan: UpgradePlans
+ seats: number
+ usingJpyPricing: boolean
+ discounted?: boolean
+}
+
+const SubscriptionCostSummary: AppComponent
= ({
+ plan,
+ seats,
+ discounted,
+ usingJpyPricing,
+ children,
+ className,
+}) => {
+ const currencyMarker = usingJpyPricing ? '¥' : '$'
+ const discount = discounted
+ ? plan === 'pro'
+ ? newUserDiscountPlans.pro
+ : newUserDiscountPlans.standard
+ : undefined
+
+ const pricePerUnit = useMemo(() => {
+ switch (plan) {
+ case 'pro':
+ return usingJpyPricing ? stripeProJpyPlanUnit : stripeProPlanUnit
+ case 'standard':
+ default:
+ return usingJpyPricing
+ ? stripeStandardJpyPlanUnit
+ : stripeStandardPlanUnit
+ }
+ }, [plan, usingJpyPricing])
+
+ const discountedPricePerUnit = useMemo(() => {
+ if (discount == null) {
+ return 0
+ }
+
+ if (!usingJpyPricing) {
+ return discount.amountOff
+ }
+
+ return discount.amountOff * 100
+ }, [discount, usingJpyPricing])
+
+ return (
+
+
+
+ {plan}
+ {currencyMarker}
+ {pricePerUnit} × {seats} {plur('member', seats)} × 1 month
+
+
+ {currencyMarker}
+ {pricePerUnit * seats}
+
+
+ {discount != null && (
+
+
+
+ {discount.durationInMonths}{' '}
+ {plur('month', discount.durationInMonths)} discount
+
+
+ -{discount.percentageOff}%
+
+
+ )}
+
+
+ Total Monthly Price
+
+
+ {currencyMarker}
+ {pricePerUnit * seats - discountedPricePerUnit * seats}
+
+
+ {children}
+
+ )
+}
+
+const Container = styled.div`
+ display: flex;
+ flex-direction: column;
+ font-size: ${({ theme }) => theme.sizes.fonts.md}px;
+
+ .subscription__cost__summary__discount__icon {
+ margin-right: ${({ theme }) => theme.sizes.spaces.sm}px;
+ }
+
+ .subscription__cost__summary__row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: ${({ theme }) => theme.sizes.spaces.sm}px 0;
+ border-top: 1px solid transparent;
+ border-bottom: 1px dashed ${({ theme }) => theme.colors.border.main};
+ color: ${({ theme }) => theme.colors.text.secondary};
+ }
+
+ .subscription__cost__summary__row + .subscription__cost__summary__row {
+ border-top: 1px dashed ${({ theme }) => theme.colors.border.main};
+ }
+
+ .subscription__cost__summary__row__description {
+ display: flex;
+ align-items: center;
+ }
+
+ .subscription__cost__summary__plan {
+ display: inline-block;
+ text-transform: capitalize;
+ margin-right: ${({ theme }) => theme.sizes.spaces.sm}px;
+ padding: 2px ${({ theme }) => theme.sizes.spaces.xsm}px;
+ background-color: ${({ theme }) => theme.colors.variants.info.base};
+ border-radius: 3px;
+ color: ${({ theme }) => theme.colors.variants.info.text};
+ font-size: ${({ theme }) => theme.sizes.fonts.xsm}px;
+ }
+
+ .subscription__cost__summary__row--total {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: ${({ theme }) => theme.sizes.spaces.sm}px 0;
+ border-bottom: 2px solid ${({ theme }) => theme.colors.border.main};
+ font-size: ${({ theme }) => theme.sizes.fonts.l}px;
+ }
+`
+
+export default SubscriptionCostSummary
diff --git a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx b/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
index 07eb900767..6e8bf4e5fa 100644
--- a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
+++ b/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
@@ -1,5 +1,4 @@
import { mdiOpenInNew } from '@mdi/js'
-import plur from 'plur'
import React, { useCallback, useState } from 'react'
import Icon from '../../../../components/atoms/Icon'
import Spinner from '../../../../components/atoms/Spinner'
@@ -11,24 +10,14 @@ import { SerializedSubscription } from '../../../interfaces/db/subscription'
import { SerializedTeam } from '../../../interfaces/db/team'
import { getFormattedDateFromUnixTimestamp } from '../../../lib/date'
import { usePage } from '../../../lib/stores/pageStore'
-import {
- stripeProPlanUnit,
- stripeStandardPlanUnit,
- UpgradePlans,
- stripeProJpyPlanUnit,
- stripeStandardJpyPlanUnit,
-} from '../../../lib/stripe'
+import { UpgradePlans } from '../../../lib/stripe'
import styled from '../../../lib/styled'
import Button from '../../atoms/Button'
import Flexbox from '../../atoms/Flexbox'
-import {
- StyledCalcuration,
- StyledTotal,
- StyledUpgradePlan,
-} from '../../molecules/SubscriptionForm'
import { SectionIntroduction } from '../settings/styled'
import PlanTables from './PlanTables'
import Alert from '../../../../components/atoms/Alert'
+import SubscriptionCostSummary from './SubscriptionCostSummary'
interface SubscriptionManagementProps {
subscription: SerializedSubscription
@@ -134,157 +123,104 @@ const SubscriptionManagement = ({
targetedPlan === 'Pro' ? 'Upgrade' : 'Downgrade'
const usingJpyPricing = (subscription.cardBrand || '').toLowerCase() === 'jcb'
-
+ console.log(subscription)
return (
<>
-
-
- {subscription.plan === 'pro' ? (
-
-
-
- Pro
- {!usingJpyPricing
- ? `$${stripeProPlanUnit} `
- : `¥${stripeProJpyPlanUnit} `}
- × {subscription.seats}{' '}
- {plur('member', subscription.seats)} × 1 month
-
-
- {!usingJpyPricing
- ? `$${stripeProPlanUnit * subscription.seats}`
- : `¥${stripeProJpyPlanUnit * subscription.seats}`}
-
-
-
- Total Monthly Price
-
+
+
+ {usingJpyPricing && (
+
+ We can only accept JPY(Japanese Yen) when paying by JCB cards.
+
+ )}
+
+ {subscription.currentPeriodEnd !== 0 ? (
+ subscription.status === 'canceled' ? (
+
+ Your subscription will be canceled on{' '}
+ {getFormattedDateFromUnixTimestamp(
+ subscription.currentPeriodEnd
+ )}{' '}
+ upon reception of your last invoice .
+
+ ) : (
+
+ Will bill to the credit card ending in{' '}
- {!usingJpyPricing
- ? `$${stripeProPlanUnit * subscription.seats}`
- : `¥${stripeProJpyPlanUnit * subscription.seats}`}
-
-
-
- ) : subscription.plan === 'standard' ? (
-
-
-
- Standard
- {!usingJpyPricing
- ? `$${stripeStandardPlanUnit} `
- : `¥${stripeStandardJpyPlanUnit} `}
- × {subscription.seats}{' '}
- {plur('member', subscription.seats)} × 1 month
-
-
- {!usingJpyPricing
- ? `$${stripeStandardPlanUnit * subscription.seats}`
- : `¥${stripeStandardJpyPlanUnit * subscription.seats}`}
-
-
-
- Total Monthly Price
+ {subscription.last4}
+ {subscription.cardBrand != null &&
+ ` (${subscription.cardBrand})`}
+ {' '}
+ at{' '}
- {!usingJpyPricing
- ? `$${stripeStandardPlanUnit * subscription.seats}`
- : `¥${stripeStandardJpyPlanUnit * subscription.seats}`}
-
-
-
- ) : null}
- {usingJpyPricing && (
-
- We can only accept JPY(Japanese Yen) when paying by JCB cards.
-
- )}
-
- {subscription.currentPeriodEnd !== 0 ? (
- subscription.status === 'canceled' ? (
-
- Your subscription will be canceled on{' '}
{getFormattedDateFromUnixTimestamp(
subscription.currentPeriodEnd
- )}{' '}
- upon reception of your last invoice .
-
- ) : (
-
- Will bill to the credit card ending in{' '}
-
- {subscription.last4}
- {subscription.cardBrand != null &&
- ` (${subscription.cardBrand})`}
- {' '}
- at{' '}
-
- {getFormattedDateFromUnixTimestamp(
- subscription.currentPeriodEnd
- )}
-
- .{' '}
-
- Edit Card
-
-
- )
- ) : null}
+ )}
+
+ .{' '}
+
+ Edit Card
+
+
+ )
+ ) : null}
-
- Billing email is {subscription.email} .{' '}
-
- Edit Billing Email
-
-
-
- You can see the{' '}
+
+ Billing email is {subscription.email} .{' '}
+
+ Edit Billing Email
+
+
+
+ You can see the{' '}
+
+ Billing History
+ {fetchingHistory ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ Apply a coupon
+
+
+
+ {showPlanTables ? (
setShowPlanTables(false)}
>
- Billing History
- {fetchingHistory ? (
-
- ) : (
-
- )}
+ Hide
-
-
-
- Apply a coupon
+ ) : (
+ setShowPlanTables(true)}
+ >
+ Change plans
-
-
- {showPlanTables ? (
- setShowPlanTables(false)}
- >
- Hide
-
- ) : (
- setShowPlanTables(true)}
- >
- Change plans
-
- )}
-
-
-
-
+ )}
+
+
+
{showPlanTables && (
-
-
-
- ${stripeProPlanUnit} × {subscription.seats}{' '}
- {plur('member', subscription.seats)} × 1 month
-
-
-
- Total Monthly Price
- ${subscription.seats * stripeProPlanUnit}
-
-
+
>
) : (
<>
@@ -368,20 +299,13 @@ const SubscriptionManagement = ({
-
-
-
- ${stripeStandardPlanUnit} × {subscription.seats}{' '}
- {plur('member', subscription.seats)} × 1 month
-
-
-
- Total Monthly Price
-
- ${subscription.seats * stripeStandardPlanUnit}
-
-
-
+
>
)}
@@ -497,11 +421,6 @@ const StyledPopup = styled.div`
}
`
-const StyledBillingContainer = styled.div`
- width: 540px;
- margin-top: ${({ theme }) => theme.space.default}px;
-`
-
const StyledBillingDescription = styled.div`
margin-top: ${({ theme }) => theme.space.large}px;
diff --git a/src/cloud/components/organisms/settings/SubscriptionTab.tsx b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
index c3d321dc29..cf00afd2ca 100644
--- a/src/cloud/components/organisms/settings/SubscriptionTab.tsx
+++ b/src/cloud/components/organisms/settings/SubscriptionTab.tsx
@@ -125,6 +125,5 @@ const SubscriptionTab = () => {
export default SubscriptionTab
const StyledBillingContainer = styled.div`
- width: 540px;
margin-top: ${({ theme }) => theme.space.default}px;
`
diff --git a/src/cloud/components/organisms/settings/UpgradeTab.tsx b/src/cloud/components/organisms/settings/UpgradeTab.tsx
index 8fc4dab922..cc873f18e6 100644
--- a/src/cloud/components/organisms/settings/UpgradeTab.tsx
+++ b/src/cloud/components/organisms/settings/UpgradeTab.tsx
@@ -1,6 +1,5 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
-import { SectionRow } from './styled'
import { usePage } from '../../../lib/stores/pageStore'
import { PageStoreWithTeam } from '../../../interfaces/pageStore'
import { Elements } from '@stripe/react-stripe-js'
@@ -142,38 +141,41 @@ const UpgradeTab = ({
return (
+ Confirm and enter your payment information (Service provided by{' '}
+ Stripe )
+ >
+ }
body={
-
-
- {currentUserPermissions.role !== 'admin' ? (
-
- Only admins can access this content.
-
- ) : (
- !(subscription != null && subscription.status === 'active') && (
-
-
-
-
-
- )
- )}
-
-
+
+ {currentUserPermissions.role !== 'admin' ? (
+
+ Only admins can access this content.
+
+ ) : (
+ !(subscription != null && subscription.status === 'active') && (
+
+
+
+ )
+ )}
+
}
>
)
}
+const SubscriptionFormContainer = styled.div``
+
const StyledFYI = styled.p`
.type-link {
text-decoration: underline;
diff --git a/src/cloud/interfaces/db/subscription.ts b/src/cloud/interfaces/db/subscription.ts
index 0a81478faa..8d0633ffb5 100644
--- a/src/cloud/interfaces/db/subscription.ts
+++ b/src/cloud/interfaces/db/subscription.ts
@@ -5,6 +5,7 @@ export interface SerializeableSubscriptionProps {
plan: UpgradePlans
customerId: string
subscriptionId: string
+ discountId?: string
seats: number
status:
| 'active'
diff --git a/src/cloud/interfaces/db/team.ts b/src/cloud/interfaces/db/team.ts
index 9e67de14e4..2a3ecbc2ba 100644
--- a/src/cloud/interfaces/db/team.ts
+++ b/src/cloud/interfaces/db/team.ts
@@ -12,6 +12,7 @@ export interface SerializableTeamProps {
icon?: SerializedIcon
state: TeamOnboardingState
personal: boolean
+ discountId?: string
}
export interface SerializedUnserializableTeamProps {
diff --git a/src/cloud/lib/stripe.ts b/src/cloud/lib/stripe.ts
index 68ae436357..deb42699fa 100644
--- a/src/cloud/lib/stripe.ts
+++ b/src/cloud/lib/stripe.ts
@@ -13,7 +13,7 @@ type DiscountParameters = {
type Discounts = Record
-export const discountPlans: Discounts = {
+export const newUserDiscountPlans: Discounts = {
standard: {
durationInMonths: 3,
amountOff: 1,
diff --git a/src/shared/components/atoms/Button.tsx b/src/shared/components/atoms/Button.tsx
index 92a5f7f460..8f16d6b1af 100644
--- a/src/shared/components/atoms/Button.tsx
+++ b/src/shared/components/atoms/Button.tsx
@@ -211,7 +211,7 @@ const StyledButton = styled.button`
padding: 0;
border: 0;
height: auto !important;
- display: inline;
+ display: inline-flex;
.button__spinner {
border-color: ${({ theme }) => theme.colors.text.link};
diff --git a/src/shared/components/atoms/Link.tsx b/src/shared/components/atoms/Link.tsx
index e89e015413..d19d655ad6 100644
--- a/src/shared/components/atoms/Link.tsx
+++ b/src/shared/components/atoms/Link.tsx
@@ -54,7 +54,7 @@ const Container = styled.a`
transition: 200ms color;
text-decoration: none;
color: ${({ theme }) => theme.colors.text.link}
- padding: 0 ${({ theme }) => theme.sizes.spaces.sm}px;
+ padding: 0 ${({ theme }) => theme.sizes.spaces.xsm}px;
cursor: pointer;
&:hover {
diff --git a/src/shared/components/molecules/Form/atoms/FormStripeInput.tsx b/src/shared/components/molecules/Form/atoms/FormStripeInput.tsx
new file mode 100644
index 0000000000..6d4cf0090e
--- /dev/null
+++ b/src/shared/components/molecules/Form/atoms/FormStripeInput.tsx
@@ -0,0 +1,72 @@
+import React, { useMemo } from 'react'
+import cc from 'classcat'
+import styled from '../../../../lib/styled'
+import {
+ formInputHeight,
+ selectV2Theme,
+} from '../../../../lib/styled/styleFunctions'
+
+import Stripe, { StripeElementStyle } from '@stripe/stripe-js'
+import { CardElement } from '@stripe/react-stripe-js'
+import { ThemeTypes } from '../../../../lib/styled/types'
+
+export interface FormStripeInputProps {
+ id?: string
+ className?: string
+ theme: ThemeTypes
+ onChange: (event: Stripe.StripeCardElementChangeEvent) => void
+}
+
+const FormStripeInput = ({
+ className,
+ id,
+ onChange,
+ theme,
+}: FormStripeInputProps) => {
+ const stripeFormStyle: StripeElementStyle = useMemo(() => {
+ const themeProps = selectV2Theme(theme)
+ return {
+ base: {
+ fontFamily: themeProps.fonts.family,
+ fontSize: `${themeProps.sizes.fonts.df}px`,
+ color: themeProps.colors.text.primary,
+ '::placeholder': {
+ color: themeProps.colors.text.subtle,
+ },
+ ':focus': {},
+ },
+ }
+ }, [theme])
+
+ return (
+
+
+
+ )
+}
+
+export default FormStripeInput
+
+const Container = styled.div`
+ flex: 1 1 auto;
+ padding: 0 ${({ theme }) => theme.sizes.spaces.sm}px;
+ border-radius: ${({ theme }) => theme.borders.radius}px;
+ ${formInputHeight}
+ border: 1px solid ${({ theme }) => theme.colors.border.main};
+
+ .StripeElement {
+ line-height: 32px !important;
+ height: 100%;
+ margin: 0 !important;
+ display: flex !important;
+ flex-direction: row !important;
+ align-items: center !important;
+ }
+`
diff --git a/src/shared/components/molecules/Form/templates/FormRow.tsx b/src/shared/components/molecules/Form/templates/FormRow.tsx
index 89cedd49c9..2ab34cb978 100644
--- a/src/shared/components/molecules/Form/templates/FormRow.tsx
+++ b/src/shared/components/molecules/Form/templates/FormRow.tsx
@@ -23,6 +23,7 @@ export type FormRowProps = {
title?: React.ReactNode
required?: boolean
description?: React.ReactNode
+ fullWidth?: boolean
items?: (
| {
type: 'input'
@@ -41,11 +42,12 @@ export type FormRowProps = {
)[]
}
-const FormRow: AppComponent<{ row: FormRowProps }> = ({
- row,
+const FormRow: AppComponent<{ row?: FormRowProps }> = ({
+ row = { required: false, title: '', items: [] },
className,
children,
}) => {
+ const items = row.items || []
return (
= ({
])}
>
{row.title != null && {row.title}
}
- {row.items != null && (
-
- {row.items.map((item, k) => (
-
- {item.type === 'input' ? (
-
- ) : item.type === 'select' ? (
-
- ) : item.type === 'select--string' ? (
-
- ) : item.type === 'textarea' ? (
-
- ) : item.type === 'image' ? (
-
- ) : item.type === 'emoji' ? (
-
- ) : item.type === 'button' ? (
-
- {item.props.label}
-
- ) : (
- item.element
- )}
-
- ))}
- {children}
-
- )}
+
+ {items.map((item, k) => (
+
+ {item.type === 'input' ? (
+
+ ) : item.type === 'select' ? (
+
+ ) : item.type === 'select--string' ? (
+
+ ) : item.type === 'textarea' ? (
+
+ ) : item.type === 'image' ? (
+
+ ) : item.type === 'emoji' ? (
+
+ ) : item.type === 'button' ? (
+ {item.props.label}
+ ) : (
+ item.element
+ )}
+
+ ))}
+ {children}
+
{row.description != null && (
{row.description}
)}
From 3a82310d2f4622dbd0b26e246f7d06ebbe140228 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Mon, 24 May 2021 10:12:42 +0900
Subject: [PATCH 88/91] fix trial alert
---
src/cloud/components/molecules/SubscriptionForm/index.tsx | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/cloud/components/molecules/SubscriptionForm/index.tsx b/src/cloud/components/molecules/SubscriptionForm/index.tsx
index beaff36086..e92eb259a5 100644
--- a/src/cloud/components/molecules/SubscriptionForm/index.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/index.tsx
@@ -175,10 +175,7 @@ const SubscriptionForm = ({
/>
Date: Mon, 24 May 2021 10:36:54 +0900
Subject: [PATCH 89/91] remove full width in forms
---
.../molecules/SubscriptionForm/UpdateBillingEmailForm.tsx | 1 -
.../molecules/SubscriptionForm/UpdateBillingPromo.tsx | 1 -
src/cloud/components/molecules/SubscriptionForm/index.tsx | 2 --
src/shared/components/molecules/Form/templates/FormRow.tsx | 5 +----
4 files changed, 1 insertion(+), 8 deletions(-)
diff --git a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx
index e4c62f5225..ab50581082 100644
--- a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx
@@ -76,7 +76,6 @@ const UpdateBillingEmailForm = ({
= ({
{items.map((item, k) => (
From da67cfd254e4ce0e0dc7212e940368c8fa5cfc73 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Mon, 24 May 2021 14:26:21 +0900
Subject: [PATCH 90/91] front end
---
src/cloud/components/Application.tsx | 2 +-
.../UpdateBillingEmailForm.tsx | 7 +--
.../UpdateBillingMethodForm.tsx | 7 +--
.../SubscriptionForm/UpdateBillingPromo.tsx | 14 +++--
.../molecules/SubscriptionForm/index.tsx | 54 +++++++++++-----
.../organisms/FreeTrialPopup/index.tsx | 23 ++++---
.../organisms/Subscription/PlanTables.tsx | 29 ++++++---
.../Subscription/SubscriptionCostSummary.tsx | 30 +++------
.../Subscription/SubscriptionManagement.tsx | 61 ++++++++++++++++---
src/cloud/interfaces/db/subscription.ts | 2 +-
src/cloud/interfaces/db/team.ts | 2 +-
src/cloud/lib/consts.ts | 3 +
src/cloud/lib/stripe.ts | 18 +++---
src/shared/components/atoms/Button.tsx | 35 +++++++++++
webpack.cloud.config.ts | 2 +
15 files changed, 197 insertions(+), 92 deletions(-)
diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx
index 3cd34f95fa..a6ec327571 100644
--- a/src/cloud/components/Application.tsx
+++ b/src/cloud/components/Application.tsx
@@ -148,7 +148,7 @@ const Application = ({
useEffectOnce(() => {
if (query.settings === 'upgrade') {
- openSettingsTab('teamUpgrade')
+ openSettingsTab('teamUpgrade', { initialPlan: 'pro', tabState: 'form' })
}
})
diff --git a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx
index ab50581082..1ae3307bc1 100644
--- a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingEmailForm.tsx
@@ -88,12 +88,7 @@ const UpdateBillingEmailForm = ({
],
}}
/>
-
+
Cancel
diff --git a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingMethodForm.tsx b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingMethodForm.tsx
index c000bf1c89..2f0337fda5 100644
--- a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingMethodForm.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingMethodForm.tsx
@@ -136,12 +136,7 @@ const UpdateBillingMethodForm = ({
/>
-
+
Cancel
diff --git a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx
index 07bf61697c..f788471727 100644
--- a/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/UpdateBillingPromo.tsx
@@ -10,6 +10,8 @@ import ButtonGroup from '../../../../shared/components/atoms/ButtonGroup'
import Form from '../../../../shared/components/molecules/Form'
import FormRow from '../../../../shared/components/molecules/Form/templates/FormRow'
import styled from '../../../../shared/lib/styled'
+import Banner from '../../../../shared/components/atoms/Banner'
+import { mdiGiftOff } from '@mdi/js'
interface UpdateBillingPromoFormProps {
sub?: SerializedSubscription
@@ -79,6 +81,11 @@ const UpdateBillingPromoForm = ({
return (
+ {sub.couponId != null && (
+
+ Applying a promotion code will end your current discount
+
+ )}
Apply a promotion code
-
+
Cancel
diff --git a/src/cloud/components/molecules/SubscriptionForm/index.tsx b/src/cloud/components/molecules/SubscriptionForm/index.tsx
index a385a0e8b1..858cf53cad 100644
--- a/src/cloud/components/molecules/SubscriptionForm/index.tsx
+++ b/src/cloud/components/molecules/SubscriptionForm/index.tsx
@@ -6,7 +6,7 @@ import { SerializedSubscription } from '../../../interfaces/db/subscription'
import Stripe from '@stripe/stripe-js'
import { useSettings } from '../../../lib/stores/settings'
import { usePage } from '../../../lib/stores/pageStore'
-import { UpgradePlans } from '../../../lib/stripe'
+import { discountPlans, UpgradePlans } from '../../../lib/stripe'
import Alert from '../../../../components/atoms/Alert'
import { useToast } from '../../../../shared/lib/stores/toast'
import Button, {
@@ -20,6 +20,7 @@ import Form from '../../../../shared/components/molecules/Form'
import styled from '../../../../shared/lib/styled'
import FormStripeInput from '../../../../shared/components/molecules/Form/atoms/FormStripeInput'
import { mdiChevronDown, mdiChevronRight } from '@mdi/js'
+import Banner from '../../../../shared/components/atoms/Banner'
interface SubscriptionFormProps {
team: SerializedTeam
@@ -136,6 +137,21 @@ const SubscriptionForm = ({
const numberOfMembers = permissions.length
+ const eligibleDiscount = useMemo(() => {
+ if (!isEligibleForDiscount(team)) {
+ return
+ }
+
+ switch (currentPlan) {
+ case 'pro':
+ return discountPlans.newUserPro
+ case 'standard':
+ return discountPlans.newUserStandard
+ default:
+ return
+ }
+ }, [currentPlan, team])
+
return (
@@ -143,7 +159,7 @@ const SubscriptionForm = ({
usingJpyPricing={usingJpyPricing}
plan={currentPlan}
seats={numberOfMembers}
- discounted={isEligibleForDiscount(team)}
+ discount={eligibleDiscount}
/>
{usingJpyPricing && (
@@ -191,20 +207,28 @@ const SubscriptionForm = ({
{showPromoCode && (
-
+ {isEligibleForDiscount(team) && (
+
+ Applying a promotion code will prevent you to receive other
+ discounts
+
+ )}
+
+ ],
+ }}
+ />
+ >
)}
{onCancel != null && (
diff --git a/src/cloud/components/organisms/FreeTrialPopup/index.tsx b/src/cloud/components/organisms/FreeTrialPopup/index.tsx
index 1df4ff098d..11761f3f9d 100644
--- a/src/cloud/components/organisms/FreeTrialPopup/index.tsx
+++ b/src/cloud/components/organisms/FreeTrialPopup/index.tsx
@@ -1,6 +1,5 @@
import React, { useState, useCallback } from 'react'
import styled from '../../../lib/styled'
-import CustomButton from '../../atoms/buttons/CustomButton'
import Flexbox from '../../atoms/Flexbox'
import Spinner from '../../atoms/CustomSpinner'
import { startTeamFreeTrial } from '../../../api/teams/subscription/trial'
@@ -8,6 +7,7 @@ import { SerializedTeam } from '../../../interfaces/db/team'
import { usePage } from '../../../lib/stores/pageStore'
import { freeTrialPeriodDays } from '../../../lib/subscription'
import { useToast } from '../../../../shared/lib/stores/toast'
+import Button from '../../../../shared/components/atoms/Button'
interface FreeTrialPopupProps {
team: SerializedTeam
@@ -56,8 +56,8 @@ const FreeTrialPopup = ({ team, close }: FreeTrialPopupProps) => {
No credit card information is necessary for now.
-
-
+ {
) : (
'Start Free Trial'
)}
-
-
+
Cancel
-
+
@@ -96,6 +96,15 @@ const StyledFreeTrialPopup = styled.div`
right: 0;
bottom: 0;
overflow: hidden;
+ .button__group {
+ button {
+ margin: 0;
+ }
+
+ button + button {
+ margin-top: 8px;
+ }
+ }
`
const StyledFreeTrialPopupBackground = styled.div`
diff --git a/src/cloud/components/organisms/Subscription/PlanTables.tsx b/src/cloud/components/organisms/Subscription/PlanTables.tsx
index 8dcd8b20f7..ec89830240 100644
--- a/src/cloud/components/organisms/Subscription/PlanTables.tsx
+++ b/src/cloud/components/organisms/Subscription/PlanTables.tsx
@@ -4,10 +4,10 @@ import { useMediaQuery } from 'react-responsive'
import { SerializedSubscription } from '../../../interfaces/db/subscription'
import { SerializedTeam } from '../../../interfaces/db/team'
import {
+ discountPlans,
stripeProPlanUnit,
stripeStandardPlanUnit,
UpgradePlans,
- newUserDiscountPlans,
} from '../../../lib/stripe'
import {
freePlanDocLimit,
@@ -137,8 +137,11 @@ const PlanTables = ({
{discounted && (
$
- {stripeStandardPlanUnit -
- newUserDiscountPlans.standard.amountOff}
+ {Math.round(
+ stripeStandardPlanUnit -
+ stripeStandardPlanUnit *
+ (discountPlans.newUserStandard.percentageOff / 100)
+ )}
)}
@@ -148,9 +151,9 @@ const PlanTables = ({
{discounted && (
- {newUserDiscountPlans.standard.percentageOff}% OFF for{' '}
- {newUserDiscountPlans.standard.durationInMonths}{' '}
- {plur('month', newUserDiscountPlans.standard.durationInMonths)}
+ {discountPlans.newUserStandard.percentageOff}% OFF for{' '}
+ {discountPlans.newUserStandard.durationInMonths}{' '}
+ {plur('month', discountPlans.newUserStandard.durationInMonths)}
)}
@@ -200,7 +203,12 @@ const PlanTables = ({
{discounted && (
- ${stripeProPlanUnit - newUserDiscountPlans.pro.amountOff}
+ $
+ {Math.round(
+ stripeProPlanUnit -
+ stripeProPlanUnit *
+ (discountPlans.newUserPro.percentageOff / 100)
+ )}
)}
@@ -210,9 +218,9 @@ const PlanTables = ({
{discounted && (
- {newUserDiscountPlans.pro.percentageOff}% OFF for{' '}
- {newUserDiscountPlans.pro.durationInMonths}{' '}
- {plur('month', newUserDiscountPlans.pro.durationInMonths)}
+ {discountPlans.newUserPro.percentageOff}% OFF for{' '}
+ {discountPlans.newUserPro.durationInMonths}{' '}
+ {plur('month', discountPlans.newUserPro.durationInMonths)}
)}
@@ -258,6 +266,7 @@ const Container = styled.div`
flex-direction: row;
flex-wrap: nowrap;
flex: 1 1 auto;
+ font-size: ${({ theme }) => theme.sizes.fonts.df}px;
.plan__item__footer {
position: absolute;
diff --git a/src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx b/src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx
index c0da4ab88f..ab731cecb5 100644
--- a/src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx
+++ b/src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx
@@ -9,7 +9,7 @@ import {
stripeStandardJpyPlanUnit,
stripeStandardPlanUnit,
UpgradePlans,
- newUserDiscountPlans,
+ CloudDiscountParameters,
} from '../../../lib/stripe'
import Icon from '../../../../shared/components/atoms/Icon'
import { mdiGiftOutline } from '@mdi/js'
@@ -18,23 +18,18 @@ interface SubscriptionCostSummaryProps {
plan: UpgradePlans
seats: number
usingJpyPricing: boolean
- discounted?: boolean
+ discount?: CloudDiscountParameters
}
const SubscriptionCostSummary: AppComponent
= ({
plan,
seats,
- discounted,
+ discount,
usingJpyPricing,
children,
className,
}) => {
const currencyMarker = usingJpyPricing ? '¥' : '$'
- const discount = discounted
- ? plan === 'pro'
- ? newUserDiscountPlans.pro
- : newUserDiscountPlans.standard
- : undefined
const pricePerUnit = useMemo(() => {
switch (plan) {
@@ -48,18 +43,6 @@ const SubscriptionCostSummary: AppComponent = ({
}
}, [plan, usingJpyPricing])
- const discountedPricePerUnit = useMemo(() => {
- if (discount == null) {
- return 0
- }
-
- if (!usingJpyPricing) {
- return discount.amountOff
- }
-
- return discount.amountOff * 100
- }, [discount, usingJpyPricing])
-
return (
@@ -95,7 +78,12 @@ const SubscriptionCostSummary: AppComponent = ({
{currencyMarker}
- {pricePerUnit * seats - discountedPricePerUnit * seats}
+ {Math.round(
+ pricePerUnit * seats -
+ pricePerUnit *
+ seats *
+ (discount == null ? 0 : discount.percentageOff / 100)
+ )}
{children}
diff --git a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx b/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
index 6e8bf4e5fa..81589f1c37 100644
--- a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
+++ b/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
@@ -1,5 +1,5 @@
-import { mdiOpenInNew } from '@mdi/js'
-import React, { useCallback, useState } from 'react'
+import { mdiGiftOff, mdiOpenInNew } from '@mdi/js'
+import React, { useCallback, useMemo, useState } from 'react'
import Icon from '../../../../components/atoms/Icon'
import Spinner from '../../../../components/atoms/Spinner'
import { useToast } from '../../../../shared/lib/stores/toast'
@@ -10,14 +10,19 @@ import { SerializedSubscription } from '../../../interfaces/db/subscription'
import { SerializedTeam } from '../../../interfaces/db/team'
import { getFormattedDateFromUnixTimestamp } from '../../../lib/date'
import { usePage } from '../../../lib/stores/pageStore'
-import { UpgradePlans } from '../../../lib/stripe'
+import { discountPlans, UpgradePlans } from '../../../lib/stripe'
import styled from '../../../lib/styled'
-import Button from '../../atoms/Button'
import Flexbox from '../../atoms/Flexbox'
import { SectionIntroduction } from '../settings/styled'
import PlanTables from './PlanTables'
import Alert from '../../../../components/atoms/Alert'
import SubscriptionCostSummary from './SubscriptionCostSummary'
+import Banner from '../../../../shared/components/atoms/Banner'
+import Button from '../../../../shared/components/atoms/Button'
+import {
+ newUserProCouponId,
+ newUserStandardCouponId,
+} from '../../../lib/consts'
interface SubscriptionManagementProps {
subscription: SerializedSubscription
@@ -123,7 +128,25 @@ const SubscriptionManagement = ({
targetedPlan === 'Pro' ? 'Upgrade' : 'Downgrade'
const usingJpyPricing = (subscription.cardBrand || '').toLowerCase() === 'jcb'
- console.log(subscription)
+
+ const currentSubscriptionDiscount = useMemo(() => {
+ if (subscription.couponId == null) {
+ return
+ }
+
+ console.log(subscription.couponId)
+ console.log(newUserProCouponId)
+ console.log(newUserStandardCouponId)
+ switch (subscription.couponId) {
+ case newUserProCouponId:
+ return discountPlans.newUserPro
+ case newUserStandardCouponId:
+ return discountPlans.newUserStandard
+ default:
+ return discountPlans.migration
+ }
+ }, [subscription.couponId])
+
return (
<>
@@ -131,7 +154,7 @@ const SubscriptionManagement = ({
plan={subscription.plan}
seats={subscription.seats}
usingJpyPricing={usingJpyPricing}
- discounted={subscription.discountId != null}
+ discount={currentSubscriptionDiscount}
/>
{usingJpyPricing && (
@@ -246,6 +269,11 @@ const SubscriptionManagement = ({
{subscriptionPlanChange} to {targetedPlan}
+ {currentSubscriptionDiscount?.percentageOff !== 100 && (
+
+ Changing plans will end your current discount.
+
+ )}
{targetedPlan === 'Free' ? (
<>
@@ -277,7 +305,6 @@ const SubscriptionManagement = ({
className='popup__billing'
seats={subscription.seats}
plan={'pro'}
- discounted={subscription.discountId != null}
usingJpyPricing={usingJpyPricing}
/>
>
@@ -303,13 +330,16 @@ const SubscriptionManagement = ({
className='popup__billing'
seats={subscription.seats}
plan={'standard'}
- discounted={subscription.discountId != null}
usingJpyPricing={usingJpyPricing}
/>
>
)}
-
+
setTargetedPlan(undefined)}
disabled={sending}
@@ -351,6 +381,17 @@ const StyledPopup = styled.div`
right: 0;
bottom: 0;
overflow: hidden;
+ font-size: 13px;
+
+ .button__group {
+ button {
+ margin: 0;
+ }
+
+ button + button {
+ margin-top: 8px;
+ }
+ }
.popup__background {
z-index: 8011;
diff --git a/src/cloud/interfaces/db/subscription.ts b/src/cloud/interfaces/db/subscription.ts
index 8d0633ffb5..7bad6570dd 100644
--- a/src/cloud/interfaces/db/subscription.ts
+++ b/src/cloud/interfaces/db/subscription.ts
@@ -5,7 +5,7 @@ export interface SerializeableSubscriptionProps {
plan: UpgradePlans
customerId: string
subscriptionId: string
- discountId?: string
+ couponId?: string
seats: number
status:
| 'active'
diff --git a/src/cloud/interfaces/db/team.ts b/src/cloud/interfaces/db/team.ts
index 2a3ecbc2ba..0a98b375c5 100644
--- a/src/cloud/interfaces/db/team.ts
+++ b/src/cloud/interfaces/db/team.ts
@@ -12,7 +12,7 @@ export interface SerializableTeamProps {
icon?: SerializedIcon
state: TeamOnboardingState
personal: boolean
- discountId?: string
+ couponId?: string
}
export interface SerializedUnserializableTeamProps {
diff --git a/src/cloud/lib/consts.ts b/src/cloud/lib/consts.ts
index 25c77e592e..d7ae1ee5da 100644
--- a/src/cloud/lib/consts.ts
+++ b/src/cloud/lib/consts.ts
@@ -9,3 +9,6 @@ export const stripePublishableKey =
process.env.STRIPE_PUBLISHABLE_KEY || 'elidid'
export const githubOauthId = process.env.GITHUB_OAUTH_ID || 'elidid'
export const googleClientId = process.env.GOOGLE_CLIENT_ID || 'elidid'
+
+export const newUserStandardCouponId = process.env.COUPONS_NEW_USER_STANDARD
+export const newUserProCouponId = process.env.COUPONS_NEW_USER_PRO
diff --git a/src/cloud/lib/stripe.ts b/src/cloud/lib/stripe.ts
index deb42699fa..1b5d79912e 100644
--- a/src/cloud/lib/stripe.ts
+++ b/src/cloud/lib/stripe.ts
@@ -5,23 +5,25 @@ export const stripeStandardJpyPlanUnit = 300
export type UpgradePlans = 'standard' | 'pro'
-type DiscountParameters = {
+export type CloudDiscountParameters = {
durationInMonths: number
- amountOff: number
percentageOff: number
}
-type Discounts = Record
+type DiscountPlan = 'newUserStandard' | 'newUserPro' | 'migration'
+export type CloudDiscounts = Record
-export const newUserDiscountPlans: Discounts = {
- standard: {
+export const discountPlans: CloudDiscounts = {
+ newUserStandard: {
durationInMonths: 3,
- amountOff: 1,
percentageOff: 33,
},
- pro: {
+ newUserPro: {
durationInMonths: 3,
- amountOff: 4,
percentageOff: 50,
},
+ migration: {
+ durationInMonths: 1,
+ percentageOff: 100,
+ },
}
diff --git a/src/shared/components/atoms/Button.tsx b/src/shared/components/atoms/Button.tsx
index 8f16d6b1af..1e2dfbafa7 100644
--- a/src/shared/components/atoms/Button.tsx
+++ b/src/shared/components/atoms/Button.tsx
@@ -18,6 +18,7 @@ export type ButtonVariant =
| 'link'
| 'transparent'
| 'warning'
+ | 'bordered'
export interface ButtonProps {
variant?: ButtonVariant
@@ -275,6 +276,39 @@ const StyledButton = styled.button`
}
}
+ &.button__variant--bordered {
+ background; transparent;
+ color: ${({ theme }) => theme.colors.text.secondary};
+ border: 1px solid ${({ theme }) => theme.colors.border.second};
+
+ .button__spinner {
+ border-color: ${({ theme }) => theme.colors.text.secondary};
+ border-right-color: transparent;
+ }
+
+ &:not(.button__state--disabled) {
+ &.focus {
+ background: ${({ theme }) => theme.colors.variants.secondary.base};
+ color: background: ${({ theme }) =>
+ theme.colors.variants.secondary.text};
+ filter: brightness(103%);
+ }
+ &:hover {
+ background: ${({ theme }) => theme.colors.variants.secondary.base};
+ color: background: ${({ theme }) =>
+ theme.colors.variants.secondary.text};
+ filter: brightness(106%);
+ }
+ &:active,
+ &.button__state--active {
+ background: ${({ theme }) => theme.colors.variants.secondary.base};
+ color: background: ${({ theme }) =>
+ theme.colors.variants.secondary.text};
+ filter: brightness(112%);
+ }
+ }
+ }
+
&.button__variant--warning {
background-color: ${({ theme }) => theme.colors.variants.warning.base};
color: ${({ theme }) => theme.colors.variants.warning.text};
@@ -341,6 +375,7 @@ const StyledButton = styled.button`
}
}
}
+
&.button__size--lg {
height: 40px;
diff --git a/webpack.cloud.config.ts b/webpack.cloud.config.ts
index 07cc4a0864..f3ee7bf8fb 100644
--- a/webpack.cloud.config.ts
+++ b/webpack.cloud.config.ts
@@ -74,6 +74,8 @@ module.exports = (env, argv) => {
'GOOGLE_CLIENT_ID',
'INTERCOM_APP_ID',
'STRIPE_PUBLISHABLE_KEY',
+ 'COUPONS_NEW_USER_STANDARD',
+ 'COUPONS_NEW_USER_PRO',
]),
new CopyPlugin({
patterns: [
From f99b97f566ef0c3153b450e6b911bfe905e8a907 Mon Sep 17 00:00:00 2001
From: davy-c
Date: Mon, 24 May 2021 14:30:59 +0900
Subject: [PATCH 91/91] remove dev stuff
---
src/cloud/components/Application.tsx | 2 +-
.../organisms/Subscription/SubscriptionManagement.tsx | 3 ---
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx
index a6ec327571..3cd34f95fa 100644
--- a/src/cloud/components/Application.tsx
+++ b/src/cloud/components/Application.tsx
@@ -148,7 +148,7 @@ const Application = ({
useEffectOnce(() => {
if (query.settings === 'upgrade') {
- openSettingsTab('teamUpgrade', { initialPlan: 'pro', tabState: 'form' })
+ openSettingsTab('teamUpgrade')
}
})
diff --git a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx b/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
index 81589f1c37..74d9af1945 100644
--- a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
+++ b/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx
@@ -134,9 +134,6 @@ const SubscriptionManagement = ({
return
}
- console.log(subscription.couponId)
- console.log(newUserProCouponId)
- console.log(newUserStandardCouponId)
switch (subscription.couponId) {
case newUserProCouponId:
return discountPlans.newUserPro