diff --git a/client/src/context/personalQuotaContext.ts b/client/src/context/personalQuotaContext.ts index aacf7cb2cd..9e9f68aa9c 100644 --- a/client/src/context/personalQuotaContext.ts +++ b/client/src/context/personalQuotaContext.ts @@ -7,6 +7,7 @@ type ContextType = { allowed: number; }; isSubscribed: boolean; + isPastDue: boolean; hasCheckedQuota: boolean; resetAt: string; }; @@ -19,6 +20,7 @@ export const PersonalQuotaContext = { allowed: 10, }, isSubscribed: false, + isPastDue: false, hasCheckedQuota: false, resetAt: new Date().toISOString(), }), diff --git a/client/src/context/providers/PersonalQuotaContextProvider.tsx b/client/src/context/providers/PersonalQuotaContextProvider.tsx index c80aed388f..eef43a3da3 100644 --- a/client/src/context/providers/PersonalQuotaContextProvider.tsx +++ b/client/src/context/providers/PersonalQuotaContextProvider.tsx @@ -19,6 +19,7 @@ export const PersonalQuotaContextProvider = memo( const [quota, setQuota] = useState({ used: 0, allowed: 10 }); const [requestsLeft, setRequestsLeft] = useState(10); const [isSubscribed, setIsSubscribed] = useState(false); + const [isPastDue, setIsPastDue] = useState(false); const [hasCheckedQuota, setHasCheckedQuota] = useState(false); const [resetAt, setResetAt] = useState(new Date().toISOString()); const { isSelfServe, envConfig } = useContext(DeviceContext); @@ -27,6 +28,7 @@ export const PersonalQuotaContextProvider = memo( if (!isSelfServe && envConfig.user_login) { const resp = await getQuota(); setIsSubscribed(resp.upgraded); + setIsPastDue(resp.isPastDue); setQuota((prev) => { const newState = { used: resp.used, allowed: resp.allowed }; if (JSON.stringify(prev) === JSON.stringify(newState)) { @@ -56,10 +58,11 @@ export const PersonalQuotaContextProvider = memo( requestsLeft, quota, isSubscribed, + isPastDue, hasCheckedQuota, resetAt, }), - [requestsLeft, isSubscribed, hasCheckedQuota, quota, resetAt], + [requestsLeft, isSubscribed, isPastDue, hasCheckedQuota, quota, resetAt], ); const handlersContextValue = useMemo( diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 06bd0b8573..7ad422b036 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -431,5 +431,6 @@ "Cloning": "Cloning", "Directories": "Directories", "Languages": "Languages", - "Generating answer...": "Generating answer..." + "Generating answer...": "Generating answer...", + "Your subscription has expired. Please update your payment details to avoid being unsubscribed.": "Your subscription has expired. Please update your payment details to avoid being unsubscribed." } \ No newline at end of file diff --git a/client/src/locales/es.json b/client/src/locales/es.json index 428e866636..0185c539e4 100644 --- a/client/src/locales/es.json +++ b/client/src/locales/es.json @@ -432,5 +432,6 @@ "Cloning": "Clonación", "Directories": "Directorios", "Languages": "Lenguas", - "Generating answer...": "Generando respuesta ..." + "Generating answer...": "Generando respuesta ...", + "Your subscription has expired. Please update your payment details to avoid being unsubscribed.": "Su suscripción ha expirado. Actualice sus detalles de pago para evitar no suscribirse." } \ No newline at end of file diff --git a/client/src/locales/it.json b/client/src/locales/it.json index f89567a07a..251eddd5b1 100644 --- a/client/src/locales/it.json +++ b/client/src/locales/it.json @@ -415,5 +415,6 @@ "Cloning": "Clonazione", "Directories": "Directory", "Languages": "Le lingue", - "Generating answer...": "Risposta di generazione ..." + "Generating answer...": "Risposta di generazione ...", + "Your subscription has expired. Please update your payment details to avoid being unsubscribed.": "Il tuo abbonamento è scaduto. Aggiorna i dettagli del pagamento per evitare di essere annullati." } \ No newline at end of file diff --git a/client/src/locales/ja.json b/client/src/locales/ja.json index f34180cd6f..0846aa0738 100644 --- a/client/src/locales/ja.json +++ b/client/src/locales/ja.json @@ -429,5 +429,6 @@ "Cloning": "クローニング", "Directories": "ディレクトリ", "Languages": "言語", - "Generating answer...": "答えを生成します..." + "Generating answer...": "答えを生成します...", + "Your subscription has expired. Please update your payment details to avoid being unsubscribed.": "あなたのサブスクリプションが期限切れになりました。 登録解除されないように、支払いの詳細を更新してください。" } \ No newline at end of file diff --git a/client/src/locales/zh-CN.json b/client/src/locales/zh-CN.json index 0017c248e6..4c3daca479 100644 --- a/client/src/locales/zh-CN.json +++ b/client/src/locales/zh-CN.json @@ -438,5 +438,6 @@ "Cloning": "克隆", "Directories": "目录", "Languages": "语言", - "Generating answer...": "生成答案..." + "Generating answer...": "生成答案...", + "Your subscription has expired. Please update your payment details to avoid being unsubscribed.": "您的订阅已过期。 请更新您的付款详细信息,以避免被取消订阅。" } \ No newline at end of file diff --git a/client/src/pages/HomeTab/Content.tsx b/client/src/pages/HomeTab/Content.tsx index 273ec570da..a7786dd396 100644 --- a/client/src/pages/HomeTab/Content.tsx +++ b/client/src/pages/HomeTab/Content.tsx @@ -8,7 +8,7 @@ import React, { import { Trans, useTranslation } from 'react-i18next'; import LiteLoader from '../../components/Loaders/LiteLoader'; import Button from '../../components/Button'; -import { CloseSign, Info } from '../../icons'; +import { CloseSign, Info, WarningSign } from '../../icons'; import { RepositoriesContext } from '../../context/repositoriesContext'; import { CodeStudioShortType, RepoType, SyncStatus } from '../../types/general'; import { DeviceContext } from '../../context/deviceContext'; @@ -20,6 +20,7 @@ import { postCodeStudio, } from '../../services/api'; import { UIContext } from '../../context/uiContext'; +import { PersonalQuotaContext } from '../../context/personalQuotaContext'; import AddRepos from './AddRepos'; import ReposSection from './ReposSection'; import AddRepoCard from './AddRepoCard'; @@ -43,6 +44,7 @@ const filterRepositories = (repos?: RepoType[], search?: string) => { const HomePage = ({ randomKey }: { randomKey?: any }) => { const { t } = useTranslation(); const { fetchRepos, repositories } = useContext(RepositoriesContext); + const { isPastDue } = useContext(PersonalQuotaContext.Values); const { isSelfServe } = useContext(DeviceContext); const { handleAddStudioTab } = useContext(TabsContext); const { search, filterType, setFilterType } = useContext( @@ -114,123 +116,134 @@ const HomePage = ({ randomKey }: { randomKey?: any }) => { return ( -
-
-

- Add -

-
- - - {!isSelfServe && ( - +
+ {isPastDue && ( +
+ + + Your subscription has expired. Please update your payment details + to avoid being unsubscribed. + +
+ )} +
+
+

+ Add +

+
+ + + {!isSelfServe && ( + + )} + +
+
+
+ {(filterType === 'all' || filterType === 'repos') && ( + setFilterType('repos')} + /> + )} + {(filterType === 'all' || filterType === 'studios') && ( + setFilterType('studios')} + refetchStudios={refreshCodeStudios} + handleRename={handleRename} + handleNewStudio={handleNewStudio} + /> )} - + {!!search && + ((filterType === 'all' && + !reposToShow.length && + !codeStudiosToShow.length) || + (filterType === 'repos' && !reposToShow.length) || + (filterType === 'studios' && !codeStudiosToShow.length)) && ( +
+

+ No results... +

+

+ + Nothing matched your search. Try a different combination! + +

+
+ )}
-
-
- {(filterType === 'all' || filterType === 'repos') && ( - setFilterType('repos')} - /> - )} - {(filterType === 'all' || filterType === 'studios') && ( - setFilterType('studios')} - refetchStudios={refreshCodeStudios} - handleRename={handleRename} - handleNewStudio={handleNewStudio} - /> - )} - {!!search && - ((filterType === 'all' && - !reposToShow.length && - !codeStudiosToShow.length) || - (filterType === 'repos' && !reposToShow.length) || - (filterType === 'studios' && !codeStudiosToShow.length)) && ( -
+ { + if (isSubmitted && name) { + if (studioToEdit) { + setStudioToEdit(null); + patchCodeStudio(studioToEdit.id, { name }).then( + refreshCodeStudios, + ); + } + } else if (isSubmitted) { + fetchRepos(); + setTimeout(() => fetchRepos(), 1000); + setPopupOpen('repo'); + setTimeout(() => setPopupOpen(false), 3000); + } + setStudioToEdit(null); + setAddReposOpen(null); + }} + initialValue={studioToEdit?.name} + /> + {!!popupOpen && ( +
+ {popupOpen === 'repo' ? ( + + ) : ( + + )} +

- No results... + {popupOpen === 'repo' ? ( + Syncing repository + ) : ( + Can’t open studio project + )}

-

- - Nothing matched your search. Try a different combination! - +

+ {popupOpen === 'repo' ? ( + + We are syncing your repository to bloop. This might take a + couple of minutes + + ) : ( + + One or more repositories used in this studio project is + being indexed. Try again when this process in complete. + + )}

- )} -
- { - if (isSubmitted && name) { - if (studioToEdit) { - setStudioToEdit(null); - patchCodeStudio(studioToEdit.id, { name }).then( - refreshCodeStudios, - ); - } - } else if (isSubmitted) { - fetchRepos(); - setTimeout(() => fetchRepos(), 1000); - setPopupOpen('repo'); - setTimeout(() => setPopupOpen(false), 3000); - } - setStudioToEdit(null); - setAddReposOpen(null); - }} - initialValue={studioToEdit?.name} - /> - {!!popupOpen && ( -
- {popupOpen === 'repo' ? ( - - ) : ( - - )} -
-

- {popupOpen === 'repo' ? ( - Syncing repository - ) : ( - Can’t open studio project - )} -

-

- {popupOpen === 'repo' ? ( - - We are syncing your repository to bloop. This might take a - couple of minutes - - ) : ( - - One or more repositories used in this studio project is - being indexed. Try again when this process in complete. - - )} -

+
- -
- )} + )} +
); diff --git a/client/tailwind.config.cjs b/client/tailwind.config.cjs index 4dda9dd35f..1bed5174e3 100644 --- a/client/tailwind.config.cjs +++ b/client/tailwind.config.cjs @@ -52,6 +52,7 @@ module.exports = { "danger-300": "#FB7185", "warning-100": "#F0A892", "warning-300": "#ED6E47", + "warning-300/12": "rgba(237,110,71, 0.12)", sky: '#0EA4E9', violet: '#8B5CF6', pink: '#EC4899',