Skip to content

Commit

Permalink
feat(add courierjs): add courierjs and fix typings for useCourier
Browse files Browse the repository at this point in the history
  • Loading branch information
rileylnapier committed May 14, 2024
1 parent 657026c commit e22afd0
Show file tree
Hide file tree
Showing 19 changed files with 190 additions and 115 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
]
},
"dependencies": {
"@trycourier/courier-js": "^1.4.2",
"pkg-dir": "^7.0.0"
}
}
15 changes: 12 additions & 3 deletions packages/components/src/components/CourierSdk.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect } from "react";
import { useCourier } from "@trycourier/react-provider";
import { useInbox, usePreferences } from "@trycourier/react-hooks";
import { IInbox, useInbox, usePreferences } from "@trycourier/react-hooks";
import { ToastProps } from "@trycourier/react-toast";

export const CourierSdk: React.FunctionComponent<{
activeComponents: {
Expand All @@ -9,7 +10,11 @@ export const CourierSdk: React.FunctionComponent<{
preferences: boolean;
};
}> = ({ children }) => {
const courier = useCourier();
const courier =
useCourier<{
inbox: IInbox;
toast: ToastProps;
}>();
const inbox = useInbox();
const preferences = usePreferences();

Expand Down Expand Up @@ -40,8 +45,12 @@ export const CourierSdk: React.FunctionComponent<{
...courier.toast,
},
brand: courier.brand,
transport: courier.transport,
identify: courier.identify,
renewSession: courier.renewSession,
subscribe: courier.subscribe,
track: courier.track,
transport: courier.transport,
unsubscribe: courier.unsubscribe,
};
}, [courier]);

Expand Down
10 changes: 10 additions & 0 deletions packages/components/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ declare global {
transport?: any;
brand?: Brand;
renewSession?: (token: string) => void;
identify?: (
userId: string,
payload: Record<string, unknown>
) => Promise<void>;
subscribe?: (userId: string, listId: string) => Promise<void>;
track?: (
event: string,
properties?: Record<string, unknown>
) => Promise<void>;
unsubscribe?: (userId: string, listId: string) => Promise<void>;
init: (config: ICourierConfig) => void;
on: (action: string, cb: () => void) => void;
};
Expand Down
7 changes: 2 additions & 5 deletions packages/react-inbox/src/components/Inbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const StyledTippy = styled(LazyTippy)<{

const Inbox: React.FunctionComponent<InboxProps> = (props) => {
const ref = useRef(null);
const courierContext = useCourier();
const courierContext = useCourier<{ inbox: InboxProps }>();

if (!courierContext) {
throw new Error("Missing Courier Provider");
Expand Down Expand Up @@ -143,10 +143,7 @@ const Inbox: React.FunctionComponent<InboxProps> = (props) => {
}
}

const localStorageState = useLocalStorageMessages(
courierContext.clientKey,
courierContext.userId
);
const localStorageState = useLocalStorageMessages(courierContext);

useEffect(() => {
init({
Expand Down
76 changes: 39 additions & 37 deletions packages/react-inbox/src/components/Messages2.0/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -231,39 +231,40 @@ const Header: React.FunctionComponent<IHeaderProps> = ({
};

const options = useMemo(() => {
const viewOptions = views?.map((v, index) => ({
id: v.id,
Component: ({
active,
disabled,
onClick,
selected,
showDropdown,
}: {
active?: boolean;
disabled?: boolean;
onClick?: React.MouseEventHandler;
selected?: boolean;
showDropdown?: boolean;
}) => (
<DropdownOptionButton
active={active}
onClick={onClick ?? handleSetView(v.id)}
selected={selected}
showDropdown={showDropdown}
>
<TitleWrapper
title={v.label}
unreadMessageCount={index === 0 ? unreadMessageCount : undefined}
/>
{onClick && !disabled && <DownCarrot />}
</DropdownOptionButton>
),
}));

return [
...(viewOptions ?? []),
brand?.preferenceTemplates?.length && {
const viewOptions = views
?.map((v, index) => ({
id: v.id,
Component: ({
active,
disabled,
onClick,
selected,
showDropdown,
}: {
active?: boolean;
disabled?: boolean;
onClick?: React.MouseEventHandler;
selected?: boolean;
showDropdown?: boolean;
}) => (
<DropdownOptionButton
active={active}
onClick={onClick ?? handleSetView(v.id)}
selected={selected}
showDropdown={showDropdown}
>
<TitleWrapper
title={v.label}
unreadMessageCount={index === 0 ? unreadMessageCount : undefined}
/>
{onClick && !disabled && <DownCarrot />}
</DropdownOptionButton>
),
}))
.filter(Boolean);

if (brand?.preferenceTemplates?.length) {
viewOptions?.push({
id: "preferences",
Component: ({
active,
Expand All @@ -286,12 +287,13 @@ const Header: React.FunctionComponent<IHeaderProps> = ({
{onClick && <DownCarrot />}
</DropdownOptionButton>
),
},
].filter(Boolean);
});
}
return viewOptions;
}, [brand?.preferenceTemplates?.length, title, unreadMessageCount]);

const ActiveOption = options?.find((o) => o.id === view)?.Component;
const hasDropdownOptions = options?.length > 1;
const hasDropdownOptions = Boolean(options?.length);

return (
<Container data-testid="header">
Expand All @@ -310,7 +312,7 @@ const Header: React.FunctionComponent<IHeaderProps> = ({
{showDropdown && (
<HeadingDropdownOptions>
{options
.map((o) => {
?.map((o) => {
return <o.Component active={o.id === view} key={o.id} />;
})
.filter(Boolean)}
Expand Down
11 changes: 9 additions & 2 deletions packages/react-inbox/src/hooks/use-local-storage-messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import { useEffect, useMemo } from "react";
import { useInbox } from "@trycourier/react-hooks";
import { useCourier } from "@trycourier/react-provider";

const useLocalStorageMessages = (clientKey: string, userId: string) => {
const useLocalStorageMessages = ({
clientKey,
userId,
}: {
clientKey?: string;
userId?: string;
}) => {
const { localStorage } = useCourier();
const {
lastMessagesFetched,
Expand Down Expand Up @@ -35,7 +41,8 @@ const useLocalStorageMessages = (clientKey: string, userId: string) => {
}

try {
return JSON.parse(localStorage.getItem(localStorageKey));
const item = localStorage.getItem(localStorageKey);
return item ? JSON.parse(item) : {};
} catch {
// do nothing
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { usePreferences } from "@trycourier/react-hooks";
import { DigestSchedule } from "@trycourier/react-provider";
import React, { useEffect, useState } from "react";
import styled from "styled-components";
import { DigestSchedule } from "~/types";
import formatDigest, { toUpperCaseFirstLetter } from "~/utils/format_digest";

const DigestScheduleContainer = styled.div`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ import styled from "styled-components";
import { usePreferences } from "@trycourier/react-hooks";

import { StatusPreference } from "./Status";
import {
ChannelClassification,
IPreferenceTemplate,
IRecipientPreference,
} from "../types";
import { ChannelClassification, IRecipientPreference } from "../types";
import { IPreferenceTemplate } from "@trycourier/react-provider";

const StyledItem = styled.div`
border-bottom: 1px solid #dadce0;
Expand Down
13 changes: 6 additions & 7 deletions packages/react-preferences/src/components/PreferencesV4.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import React, { Fragment, useEffect, useMemo, useState } from "react";
import styled from "styled-components";
import { usePreferences } from "@trycourier/react-hooks";
import {
ChannelClassification,
IPreferenceTemplate,
IRecipientPreference,
PreferenceStatus,
} from "~/types";
import { ChannelClassification, IRecipientPreference } from "~/types";
import { StyledToggle } from "./StyledToggle";
import Toggle from "react-toggle";
import { PreferenceSection } from "@trycourier/react-hooks";
import DigestSchedules from "./DigestSchedule";
import { useCourier } from "@trycourier/react-provider";
import {
IPreferenceTemplate,
PreferenceStatus,
useCourier,
} from "@trycourier/react-provider";

export const ChannelOption = styled.div`
display: flex;
Expand Down
3 changes: 2 additions & 1 deletion packages/react-preferences/src/components/Status.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useState } from "react";
import Toggle from "react-toggle";
import { PreferenceItemComponentFn, PreferenceStatus } from "../types";
import { PreferenceItemComponentFn } from "../types";
import { ChannelPreferences } from "./ChannelPreferences";
import { StyledToggle } from "./StyledToggle";
import { PreferenceStatus } from "@trycourier/react-provider";

export const StatusPreference: PreferenceItemComponentFn = ({
//label,
Expand Down
36 changes: 2 additions & 34 deletions packages/react-preferences/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { PreferenceStatus } from "@trycourier/react-provider";

export type Preference = "channel_preferences" | "status" | "snooze";

export type ChannelClassification =
Expand All @@ -18,8 +20,6 @@ export type PreferenceItemComponentFn = React.FunctionComponent<{
customizeDeliveryChannel?: boolean;
}>;

export type PreferenceStatus = "OPTED_IN" | "OPTED_OUT" | "REQUIRED";

export type SnoozePreference = {
start?: string;
until: string;
Expand All @@ -31,42 +31,10 @@ export interface IPreference {
channel_preferences?: Array<ChannelClassification>;
}

export interface DigestSchedule {
period: string;
repetition: string;
scheduleId: string;
default?: boolean;
start: string;
recurrence: string;
repeat?: {
frequency: number;
interval: "day" | "week" | "month" | "year";
on?: string | RepeatOn;
};
end?: number | string;
}

export interface IPreferenceTemplate {
templateName: string;
templateId: string;
defaultStatus: PreferenceStatus;
digestSchedules?: DigestSchedule[];
}

export interface IRecipientPreference {
templateId: string;
status: PreferenceStatus | null;
hasCustomRouting: boolean;
routingPreferences: Array<ChannelClassification>;
digestSchedule: string;
}

export type RepeatOn = {
sunday?: boolean;
monday?: boolean;
tuesday?: boolean;
wednesday?: boolean;
thursday?: boolean;
friday?: boolean;
saturday?: boolean;
};
2 changes: 1 addition & 1 deletion packages/react-preferences/src/utils/format_digest.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DigestSchedule, RepeatOn } from "@trycourier/react-provider";
import format from "date-fns/format";
import { DigestSchedule, RepeatOn } from "~/types";

export const toUpperCaseFirstLetter = (str: string) => {
return str.charAt(0).toUpperCase() + str.slice(1);
Expand Down
28 changes: 27 additions & 1 deletion packages/react-provider/src/hooks/use-courier-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
Events,
} from "@trycourier/client-graphql";
import { Brand, CourierTransport } from "..";
import courier from "@trycourier/courier-js";

import { ICourierContext } from "~/types";

const useCourierActions = (state, dispatch) => {
const useCourierActions = (state, dispatch): ICourierContext => {
return useMemo(() => {
const courierClient = createCourierClient({
apiUrl: state.apiUrl,
Expand All @@ -19,10 +21,34 @@ const useCourierActions = (state, dispatch) => {
userSignature: state.userSignature,
});

courier.init({
baseUrl: state.apiUrl,
authorization: state.authorization,
clientKey: state.clientKey,
userId: state.userId,
userSignature: state.userSignature,
});

const brands = Brands({ client: courierClient });
const events = Events({ client: courierClient });

return {
dispatch,
async track(
event: string,
properties?: Record<string, unknown> | undefined
) {
await courier.track(event, properties);
},
async identify(userId: string, payload: Record<string, unknown>) {
await courier.identify(userId, payload);
},
async subscribe(userId: string, listId: string) {
await courier.subscribe(userId, listId);
},
async unsubscribe(userId: string, listId: string) {
await courier.unsubscribe(userId, listId);
},
init: async (payload: Partial<ICourierContext>) => {
dispatch({
type: "root/INIT",
Expand Down
5 changes: 3 additions & 2 deletions packages/react-provider/src/hooks/use-courier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { useContext } from "react";
import { CourierContext } from "../";
import { ICourierContext } from "../types";

function useCourier<T = any>(): ICourierContext & T {
return useContext(CourierContext) as ICourierContext & T;
function useCourier<T = unknown>(): ICourierContext & T {
const context = useContext(CourierContext) as ICourierContext & T;
return context;
}

export default useCourier;
Loading

0 comments on commit e22afd0

Please sign in to comment.