Skip to content

Commit

Permalink
Merge pull request #2397 from daostack/feature/CW-2347-notion-integra…
Browse files Browse the repository at this point in the history
…tion-improvements

Notion integration completions #2347
  • Loading branch information
andreymikhadyuk authored Dec 19, 2023
2 parents bf03def + 5dfdf77 commit 5e5a318
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 34 deletions.
4 changes: 2 additions & 2 deletions src/pages/OldCommon/interfaces/CreateCommonPayload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { UploadFile } from "@/shared/interfaces";
import {
BaseRule,
CommonLink,
NotionIntegrationIntermediate,
NotionIntegrationPayloadIntermediate,
Roles,
} from "@/shared/models";
import { MemberAdmittanceLimitations } from "@/shared/models/governance/proposals";
Expand Down Expand Up @@ -64,7 +64,7 @@ export interface IntermediateUpdateCommonData {
gallery?: UploadFile[];
links?: CommonLink[];
roles?: Roles;
notion?: NotionIntegrationIntermediate;
notion?: NotionIntegrationPayloadIntermediate;
}

export interface UpdateCommonData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const DiscussionFeedCard = forwardRef<FeedItemRef, DiscussionFeedCardProps>(
commonId,
commonName,
commonImage,
commonNotion,
commonNotion: outerCommonNotion,
pinnedFeedItems,
commonMember,
isProject,
Expand Down Expand Up @@ -128,7 +128,9 @@ const DiscussionFeedCard = forwardRef<FeedItemRef, DiscussionFeedCardProps>(
fetched: isFeedItemUserMetadataFetched,
fetchFeedItemUserMetadata,
} = useFeedItemUserMetadata();
const { data: common } = useCommon(isHome ? commonId : "");
const shouldLoadCommonData =
isHome || (discussion?.notion && !outerCommonNotion);
const { data: common } = useCommon(shouldLoadCommonData ? commonId : "");
const menuItems = useMenuItems(
{
commonId,
Expand Down Expand Up @@ -159,6 +161,7 @@ const DiscussionFeedCard = forwardRef<FeedItemRef, DiscussionFeedCardProps>(
!isFeedItemUserMetadataFetched ||
!commonId;
const cardTitle = discussion?.title;
const commonNotion = outerCommonNotion ?? common?.notion;

const handleOpenChat = useCallback(() => {
if (discussion) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import "../../../../../../constants";
@import "../../../../../../styles/sizes";
@import "../../../../../../styles/mixins";

.container {
--title-color: var(--primary-text);
Expand Down Expand Up @@ -89,9 +90,9 @@
}

.title {
display: flex;
@include flex-list-with-gap(0.5rem);

align-items: center;
gap: 8px;
color: var(--title-color);
font-size: $moderate-xsmall;
line-height: 1.5rem;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import "../../../../../../styles/mixins";

.notionInfo {
display: flex;
gap: 10px;
@include flex-list-with-gap(0.5rem);
}

.link {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const FeedNotionInfo: React.FC<FeedNotionInfoProps> = (props) => {
target="_blank"
rel="noopener noreferrer"
>
Notion pageID: {notion?.pageId}
Notion page
</a>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useRoutesContext } from "@/shared/contexts";
import { useForceUpdate, useModal, useNotification } from "@/shared/hooks";
import {
FeedItemFollowState,
useCommon,
useDiscussionById,
useFeedItemUserMetadata,
useProposalById,
Expand Down Expand Up @@ -93,7 +94,7 @@ const ProposalFeedCard = forwardRef<FeedItemRef, ProposalFeedCardProps>(
commonId,
commonName,
commonImage,
commonNotion,
commonNotion: outerCommonNotion,
pinnedFeedItems,
isProject,
isPinned,
Expand Down Expand Up @@ -152,6 +153,8 @@ const ProposalFeedCard = forwardRef<FeedItemRef, ProposalFeedCardProps>(
fetched: isFeedItemUserMetadataFetched,
fetchFeedItemUserMetadata,
} = useFeedItemUserMetadata();
const shouldLoadCommonData = discussion?.notion && !outerCommonNotion;
const { data: common } = useCommon(shouldLoadCommonData ? commonId : "");
const {
isShowing: isProposalDeleteModalOpen,
onOpen: onProposalDeleteModalOpen,
Expand Down Expand Up @@ -199,6 +202,7 @@ const ProposalFeedCard = forwardRef<FeedItemRef, ProposalFeedCardProps>(
},
);
const cardTitle = discussion?.title;
const commonNotion = outerCommonNotion ?? common?.notion;

const onProposalDelete = useCallback(async () => {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,29 @@ const ProjectCreationForm: FC<ProjectCreationFormProps> = (props) => {
updateCommon: updateProject,
} = useCommonUpdate(initialCommon?.id);
const {
data: notionIntegration,
loading: isNotionIntegrationLoading,
isNotionIntegrationUpdated,
notionIntegrationErrorModalState,
disconnectNotionModalState,
fetchNotionIntegration,
setNotionIntegrationFormData,
} = useNotionIntegration({
projectId: project?.id || updatedProject?.id,
isNotionIntegrationEnabled: Boolean(initialCommon?.notion),
});
const isLoading = isProjectCreationLoading || isCommonUpdateLoading;
const isLoading =
isProjectCreationLoading ||
isCommonUpdateLoading ||
isNotionIntegrationLoading;
const error = createProjectError || updateProjectError;

useEffect(() => {
if (initialCommon?.id) {
fetchNotionIntegration(initialCommon.id);
}
}, [initialCommon?.id]);

const nonProjectCircles = useMemo(
() => removeProjectCircles(Object.values(governance?.circles || {})),
[governance?.circles],
Expand Down Expand Up @@ -206,6 +219,7 @@ const ProjectCreationForm: FC<ProjectCreationFormProps> = (props) => {
items={getConfiguration({
isProject: true,
roles,
notionIntegration,
shouldBeUnique: {
existingNames: existingProjectsNames,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Roles } from "@/shared/models";
import { NotionIntegration, Roles, SyncLeaseStatus } from "@/shared/models";
import { TextEditorSize } from "@/shared/ui-kit";
import { CreationFormItem, CreationFormItemType } from "../../../CreationForm";
import {
Expand All @@ -14,13 +14,15 @@ interface Options {
roles?: Roles;
shouldBeUnique?: { existingNames: string[] };
isImageRequired?: boolean;
notionIntegration?: NotionIntegration | null;
}

export const getConfiguration = (options: Options): CreationFormItem[] => {
const {
isProject = true,
roles,
shouldBeUnique,
notionIntegration,
isImageRequired = false,
} = options;
const type = isProject ? "Space" : "Common";
Expand Down Expand Up @@ -144,13 +146,20 @@ export const getConfiguration = (options: Options): CreationFormItem[] => {
}

if (isProject) {
const isNotionIntegrationDisabledForUpdate = Boolean(
notionIntegration &&
notionIntegration.lastSuccessfulSyncAt === null &&
notionIntegration.syncLease?.status === SyncLeaseStatus.Pending,
);

items.push({
type: CreationFormItemType.NotionIntegration,
props: {
name: "notion",
isEnabled: {
name: "notion.isEnabled",
label: "Notion database integration",
disabled: isNotionIntegrationDisabledForUpdate,
},
token: {
name: "notion.token",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import "../../../../constants";
@import "../../../../styles/sizes";
@import "../../../../styles/mixins.scss";

.container {
min-height: 3.0625rem;
Expand Down Expand Up @@ -106,6 +107,9 @@
}

.title {
@include flex-list-with-gap(0.5rem);

align-items: center;
color: var(--primary-text);
font-size: $moderate-xsmall;
line-height: 1.5rem;
Expand Down Expand Up @@ -172,3 +176,14 @@
.bottomContentRight {
display: flex;
}

.tooltipTriggerContainer {
display: inline-flex;
}

.tooltipContent {
display: flex;
flex-direction: column;
max-width: 20rem;
z-index: 3;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ import {
useFeedItemContext,
} from "@/pages/common";
import { useRoutesContext } from "@/shared/contexts";
import { NotionIcon } from "@/shared/icons";
import { PredefinedTypes } from "@/shared/models";
import {
ContextMenu,
ContextMenuRef,
TextEditorWithReinitialization as TextEditor,
TimeAgo,
Tooltip,
TooltipContent,
TooltipTrigger,
checkIsTextEditorValueEmpty,
} from "@/shared/ui-kit";
import { CommonAvatar } from "@/shared/ui-kit/CommonAvatar";
Expand Down Expand Up @@ -45,6 +49,7 @@ export const FeedItemBaseContent: FC<FeedItemBaseContentProps> = (props) => {
dmUserId,
commonId,
hasUnseenMention,
notion,
} = props;
const history = useHistory();
const { getCommonPagePath } = useRoutesContext();
Expand Down Expand Up @@ -140,13 +145,26 @@ export const FeedItemBaseContent: FC<FeedItemBaseContentProps> = (props) => {
</div>
<div className={styles.content}>
<div className={styles.topContent}>
<p
<div
className={classNames(styles.text, styles.title, {
[styles.titleActive]: isActive,
})}
>
{finalTitle || "Loading..."}
</p>
<span>{finalTitle || "Loading..."}</span>
{Boolean(notion) && (
<Tooltip placement="top-start">
<TooltipTrigger asChild>
<div className={styles.tooltipTriggerContainer}>
<NotionIcon />
</div>
</TooltipTrigger>
<TooltipContent className={styles.tooltipContent}>
<span>Notion sync</span>
<span>Database: {notion?.title}</span>
</TooltipContent>
</Tooltip>
)}
</div>
<p
className={classNames(styles.text, styles.lastActivity, {
[styles.lastActivityActive]:
Expand Down
31 changes: 29 additions & 2 deletions src/services/Notion.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
import firebase from "firebase/compat/app";
import { ApiEndpoint } from "@/shared/constants";
import { NotionIntegration } from "@/shared/models";
import {
Collection,
NotionIntegration,
NotionIntegrationPayload,
} from "@/shared/models";
import {
firestoreDataConverter,
transformFirebaseDataSingle,
} from "@/shared/utils";
import Api from "./Api";

const converter = firestoreDataConverter<NotionIntegration>();

class NotionService {
private getNotionIntegrationCollection = () =>
firebase
.firestore()
.collection(Collection.NotionIntegration)
.withConverter(converter);

public getNotionIntegrationByCommonId = async (
commonId: string,
): Promise<NotionIntegration> => {
const notionIntegration = await this.getNotionIntegrationCollection()
.doc(commonId)
.get();

return transformFirebaseDataSingle<NotionIntegration>(notionIntegration);
};

public setupIntegration = async (
commonId: string,
notion: NotionIntegration,
notion: NotionIntegrationPayload,
): Promise<void> => {
await Api.post(ApiEndpoint.AddNotionIntegration, {
...notion,
Expand Down
Loading

0 comments on commit 5e5a318

Please sign in to comment.