[WEB-5290] feat: selfhosted check (#8227)
* feat: add in common py * fix: update marketing consent screen based on is self managed flag * improvement: enhance ImagePickerPopover with dynamic tab options based on Unsplash configuration * refactor: product updates modal to include changelog * [WEB-5290] feat: implement fallback for product updates changelog with loading state and error handling --------- Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
parent
5f7ffcb37a
commit
7c74d0a403
16 changed files with 373 additions and 61 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useRef, useCallback } from "react";
|
||||
import React, { useState, useRef, useCallback, useMemo } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
|
|
@ -16,24 +16,16 @@ import { Input, Loader } from "@plane/ui";
|
|||
// helpers
|
||||
import { getFileURL } from "@plane/utils";
|
||||
// hooks
|
||||
import { useInstance } from "@/hooks/store/use-instance";
|
||||
import { useDropdownKeyDown } from "@/hooks/use-dropdown-key-down";
|
||||
// services
|
||||
import { FileService } from "@/services/file.service";
|
||||
|
||||
const tabOptions = [
|
||||
{
|
||||
key: "unsplash",
|
||||
title: "Unsplash",
|
||||
},
|
||||
{
|
||||
key: "images",
|
||||
title: "Images",
|
||||
},
|
||||
{
|
||||
key: "upload",
|
||||
title: "Upload",
|
||||
},
|
||||
];
|
||||
type TTabOption = {
|
||||
key: string;
|
||||
title: string;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
label: string | React.ReactNode;
|
||||
|
|
@ -63,6 +55,30 @@ export const ImagePickerPopover = observer(function ImagePickerPopover(props: Pr
|
|||
const ref = useRef<HTMLDivElement>(null);
|
||||
// router params
|
||||
const { workspaceSlug } = useParams();
|
||||
// store hooks
|
||||
const { config } = useInstance();
|
||||
// derived values
|
||||
const hasUnsplashConfigured = config?.has_unsplash_configured || false;
|
||||
const tabOptions: TTabOption[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
key: "unsplash",
|
||||
title: "Unsplash",
|
||||
isEnabled: hasUnsplashConfigured,
|
||||
},
|
||||
{
|
||||
key: "images",
|
||||
title: "Images",
|
||||
isEnabled: true,
|
||||
},
|
||||
{
|
||||
key: "upload",
|
||||
title: "Upload",
|
||||
isEnabled: true,
|
||||
},
|
||||
],
|
||||
[hasUnsplashConfigured]
|
||||
);
|
||||
|
||||
const { data: unsplashImages, error: unsplashError } = useSWR(
|
||||
`UNSPLASH_IMAGES_${searchParams}`,
|
||||
|
|
|
|||
32
apps/web/core/components/global/product-updates/fallback.tsx
Normal file
32
apps/web/core/components/global/product-updates/fallback.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
||||
|
||||
type TProductUpdatesFallbackProps = {
|
||||
description: string;
|
||||
variant: "cloud" | "self-managed";
|
||||
};
|
||||
|
||||
export function ProductUpdatesFallback(props: TProductUpdatesFallbackProps) {
|
||||
const { description, variant } = props;
|
||||
// derived values
|
||||
const changelogUrl =
|
||||
variant === "cloud"
|
||||
? "https://plane.so/changelog?category=cloud"
|
||||
: "https://plane.so/changelog?category=self-hosted";
|
||||
|
||||
return (
|
||||
<div className="py-8">
|
||||
<EmptyStateDetailed
|
||||
assetKey="changelog"
|
||||
description={description}
|
||||
align="center"
|
||||
actions={[
|
||||
{
|
||||
label: "Go to changelog",
|
||||
variant: "primary",
|
||||
onClick: () => window.open(changelogUrl, "_blank"),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,18 +1,15 @@
|
|||
import type { FC } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { USER_TRACKER_ELEMENTS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// ui
|
||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||
// components
|
||||
import { ProductUpdatesFooter } from "@/components/global";
|
||||
// helpers
|
||||
import { captureView } from "@/helpers/event-tracker.helper";
|
||||
// hooks
|
||||
import { useInstance } from "@/hooks/store/use-instance";
|
||||
// plane web components
|
||||
import { ProductUpdatesHeader } from "@/plane-web/components/global";
|
||||
import { ProductUpdatesChangelog } from "@/plane-web/components/global/product-updates/changelog";
|
||||
import { ProductUpdatesHeader } from "@/plane-web/components/global/product-updates/header";
|
||||
|
||||
export type ProductUpdatesModalProps = {
|
||||
isOpen: boolean;
|
||||
|
|
@ -21,8 +18,6 @@ export type ProductUpdatesModalProps = {
|
|||
|
||||
export const ProductUpdatesModal = observer(function ProductUpdatesModal(props: ProductUpdatesModalProps) {
|
||||
const { isOpen, handleClose } = props;
|
||||
const { t } = useTranslation();
|
||||
const { config } = useInstance();
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
|
|
@ -33,27 +28,7 @@ export const ProductUpdatesModal = observer(function ProductUpdatesModal(props:
|
|||
return (
|
||||
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXXXL}>
|
||||
<ProductUpdatesHeader />
|
||||
<div className="flex flex-col h-[60vh] vertical-scrollbar scrollbar-xs overflow-hidden overflow-y-scroll px-6 mx-0.5">
|
||||
{config?.instance_changelog_url && config?.instance_changelog_url !== "" ? (
|
||||
<iframe src={config?.instance_changelog_url} className="w-full h-full" />
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center w-full h-full mb-8">
|
||||
<div className="text-lg font-medium">{t("we_are_having_trouble_fetching_the_updates")}</div>
|
||||
<div className="text-sm text-custom-text-200">
|
||||
{t("please_visit")}
|
||||
<a
|
||||
data-ph-element={USER_TRACKER_ELEMENTS.CHANGELOG_REDIRECTED}
|
||||
href="https://go.plane.so/p-changelog"
|
||||
target="_blank"
|
||||
className="text-sm text-custom-primary-100 font-medium hover:text-custom-primary-200 underline underline-offset-1 outline-none"
|
||||
>
|
||||
{t("our_changelogs")}
|
||||
</a>{" "}
|
||||
{t("for_the_latest_updates")}.
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ProductUpdatesChangelog />
|
||||
<ProductUpdatesFooter />
|
||||
</ModalCore>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { AuthService } from "@/services/auth.service";
|
|||
import { CommonOnboardingHeader } from "../common";
|
||||
import { MarketingConsent } from "./consent";
|
||||
import { SetPasswordRoot } from "./set-password";
|
||||
import { useInstance } from "@/hooks/store/use-instance";
|
||||
|
||||
type Props = {
|
||||
handleStepChange: (step: EOnboardingSteps, skipInvites?: boolean) => void;
|
||||
|
|
@ -55,6 +56,7 @@ export const ProfileSetupStep = observer(function ProfileSetupStep({ handleStepC
|
|||
// store hooks
|
||||
const { data: user, updateCurrentUser } = useUser();
|
||||
const { updateUserProfile } = useUserProfile();
|
||||
const { config: instanceConfig } = useInstance();
|
||||
// form info
|
||||
const {
|
||||
getValues,
|
||||
|
|
@ -253,12 +255,14 @@ export const ProfileSetupStep = observer(function ProfileSetupStep({ handleStepC
|
|||
</Button>
|
||||
|
||||
{/* Marketing Consent */}
|
||||
<MarketingConsent
|
||||
isChecked={!!watch("has_marketing_email_consent")}
|
||||
handleChange={(has_marketing_email_consent) =>
|
||||
setValue("has_marketing_email_consent", has_marketing_email_consent)
|
||||
}
|
||||
/>
|
||||
{!instanceConfig.is_self_managed && (
|
||||
<MarketingConsent
|
||||
isChecked={!!watch("has_marketing_email_consent")}
|
||||
handleChange={(has_marketing_email_consent) =>
|
||||
setValue("has_marketing_email_consent", has_marketing_email_consent)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue