├── docs └── intro.md ├── .nvmrc ├── .prettierignore ├── packages ├── types │ ├── index.d.ts │ ├── @types │ │ ├── css │ │ │ └── index.d.ts │ │ ├── png │ │ │ └── index.d.ts │ │ ├── md │ │ │ └── index.d.ts │ │ ├── jsonnet │ │ │ └── index.d.ts │ │ ├── raw-loader │ │ │ └── index.d.ts │ │ ├── slate-soft-break │ │ │ └── index.d.ts │ │ ├── slate-soft-breaks │ │ │ └── index.d.ts │ │ ├── react-fade-in │ │ │ └── index.d.ts │ │ ├── react-color-extractor │ │ │ └── index.d.ts │ │ ├── svg │ │ │ └── index.d.ts │ │ ├── tailwind.macro │ │ │ └── index.d.ts │ │ ├── better-react-spinkit │ │ │ └── index.d.ts │ │ ├── react-top-loading-bar │ │ │ └── index.d.ts │ │ └── react-table │ │ │ └── index.d.ts │ └── package.json ├── react-inbox-next │ ├── LICENSE │ ├── README.md │ ├── src │ │ └── index.ts │ ├── .npmignore │ ├── babel.config.js │ ├── jest.config.js │ ├── tsconfig.json │ └── package.json ├── react-toast │ ├── CHANGELOG.md │ ├── src │ │ ├── global.d.ts │ │ ├── .DS_Store │ │ ├── index.tsx │ │ ├── defaults.ts │ │ ├── constants │ │ │ └── index.ts │ │ ├── lib │ │ │ └── index.ts │ │ ├── reducer.ts │ │ ├── hooks │ │ │ ├── types.ts │ │ │ └── index.ts │ │ ├── components │ │ │ ├── Body │ │ │ │ └── helpers.tsx │ │ │ └── Toast │ │ │ │ └── styled.ts │ │ ├── assets │ │ │ └── courier_icon.svg │ │ └── types.ts │ ├── .npmignore │ ├── babel.config.js │ ├── jest.config.js │ ├── tsconfig.json │ ├── LICENSE │ ├── package.json │ └── docs │ │ └── 3.props.md ├── client-graphql │ ├── src │ │ ├── inbox │ │ │ ├── README.md │ │ │ ├── mark-all-read.ts │ │ │ ├── count.ts │ │ │ ├── __tests__ │ │ │ │ ├── mark-all-read.spec.ts │ │ │ │ └── message.spec.ts │ │ │ ├── message.ts │ │ │ ├── index.ts │ │ │ └── message-lists.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── events.ts │ ├── docs │ │ └── inbox │ │ │ └── 0.overview.md │ ├── jest.config.js │ ├── tsconfig.json │ ├── babel.config.js │ ├── webpack.config.js │ └── package.json ├── react-preferences │ ├── src │ │ ├── index.ts │ │ ├── components │ │ │ ├── DeliveryChannels.tsx │ │ │ ├── SnoozePreference.tsx │ │ │ ├── index.ts │ │ │ ├── Footer.tsx │ │ │ └── Status.tsx │ │ ├── assets │ │ │ ├── social-icons │ │ │ │ ├── icon-social-facebook.svg │ │ │ │ ├── icon-social-medium.svg │ │ │ │ ├── icon-social-linkedin.svg │ │ │ │ ├── icon-social-twitter.svg │ │ │ │ └── icon-social-instagram.svg │ │ │ └── checkmark-small.svg │ │ └── types.ts │ ├── docs │ │ ├── example.com-preferences.png │ │ ├── 2.limitations.md │ │ ├── 1.easy-usage.md │ │ └── 0.overview.md │ ├── babel.config.js │ ├── tsconfig.json │ └── package.json ├── storybook │ ├── stories │ │ ├── style.css │ │ ├── elements │ │ │ ├── title.stories.tsx │ │ │ ├── index.stories.tsx │ │ │ ├── icons.stories.tsx │ │ │ └── buttons.stories.tsx │ │ ├── toast │ │ │ ├── warning.svg │ │ │ └── styled.ts │ │ ├── provider │ │ │ └── index.stories.tsx │ │ ├── inbox │ │ │ ├── custom-header.tsx │ │ │ ├── custom-components.tsx │ │ │ └── mobile.stories.tsx │ │ ├── client-graphql │ │ │ ├── index.stories.tsx │ │ │ └── examples │ │ │ │ └── count.tsx │ │ ├── getting-started │ │ │ ├── docs │ │ │ │ ├── troubleshooting.md │ │ │ │ ├── getting-started.md │ │ │ │ ├── testing-the-integration.md │ │ │ │ └── authentication.md │ │ │ └── index.stories.tsx │ │ └── brand-designer │ │ │ └── index.stories.tsx │ ├── .storybook │ │ ├── manager.js │ │ ├── theme.ts │ │ ├── main.js │ │ └── preview.js │ ├── tsconfig.json │ └── package.json ├── core │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ └── index.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── babel.config.js │ └── package.json ├── react-elements │ ├── src │ │ ├── components │ │ │ ├── modal │ │ │ │ └── index.ts │ │ │ ├── color-pickers │ │ │ │ ├── index.tsx │ │ │ │ └── medium.tsx │ │ │ ├── buttons │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ ├── button.tsx │ │ │ │ ├── link-button.tsx │ │ │ │ └── styles.ts │ │ │ ├── icons │ │ │ │ ├── index.ts │ │ │ │ ├── courier.tsx │ │ │ │ ├── courier-text-logo.tsx │ │ │ │ ├── types.ts │ │ │ │ └── make-icon.tsx │ │ │ ├── index.ts │ │ │ ├── description.tsx │ │ │ ├── input.tsx │ │ │ ├── pretty-date.tsx │ │ │ └── title.tsx │ │ ├── index.ts │ │ └── types.ts │ ├── .npmignore │ ├── babel.config.js │ ├── jest.config.js │ ├── docs │ │ ├── 0.overview.md │ │ ├── title.md │ │ ├── button.md │ │ ├── icons.md │ │ └── link-button.md │ ├── tsconfig.json │ └── package.json ├── react-inbox │ ├── src │ │ ├── global.d.ts │ │ ├── index.ts │ │ ├── constants.ts │ │ ├── assets │ │ │ ├── back.svg │ │ │ ├── options.svg │ │ │ ├── icon-settings.svg │ │ │ ├── close.svg │ │ │ └── courier_big_icon.svg │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── OptionsDropdown │ │ │ │ ├── styled.ts │ │ │ │ ├── Options.tsx │ │ │ │ └── index.tsx │ │ │ ├── Messages2.0 │ │ │ │ ├── types.ts │ │ │ │ ├── actions │ │ │ │ │ ├── styles.ts │ │ │ │ │ ├── MarkRead.tsx │ │ │ │ │ ├── MarkAllRead.tsx │ │ │ │ │ └── MarkUnread.tsx │ │ │ │ ├── LoadingMore.tsx │ │ │ │ └── LoadingMessages.tsx │ │ │ ├── Inbox │ │ │ │ └── LazyTippy.tsx │ │ │ └── StyledTippy.tsx │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-click-outside.ts │ │ │ ├── use-on-screen.ts │ │ │ ├── use-on-scroll.ts │ │ │ ├── use-hover.ts │ │ │ ├── use-window-size.ts │ │ │ ├── use-event-listener.ts │ │ │ ├── use-message-options.ts │ │ │ └── use-local-storage-messages.ts │ │ └── lib │ │ │ └── index.ts │ ├── .npmignore │ ├── __mocks__ │ │ ├── fileMock.ts │ │ └── api │ │ │ └── messages.ts │ ├── babel.config.js │ ├── jest.config.js │ ├── tsconfig.json │ ├── LICENSE │ └── package.json ├── .DS_Store ├── react-brand-designer │ ├── src │ │ ├── brand-designer │ │ │ ├── index.ts │ │ │ ├── default-theme.ts │ │ │ └── designer-header.tsx │ │ ├── index.ts │ │ └── clipboard-brand-designer.tsx │ ├── .npmignore │ ├── babel.config.js │ ├── jest.config.js │ ├── tsconfig.json │ └── package.json ├── components │ ├── src │ │ ├── components │ │ │ ├── Inbox.ts │ │ │ ├── Toast.ts │ │ │ ├── Footer.ts │ │ │ ├── Header.ts │ │ │ ├── Preferences.ts │ │ │ ├── UnsubscribePage.tsx │ │ │ ├── PreferencePage.tsx │ │ │ └── CourierSdk.tsx │ │ └── lib │ │ │ └── get-attrs-as-json.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── babel.config.js │ └── package.json ├── react-provider │ ├── src │ │ ├── constants │ │ │ └── index.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-courier.ts │ │ │ ├── use-page-visible.ts │ │ │ ├── use-is-online.ts │ │ │ ├── use-listen-for-transport.ts │ │ │ ├── use-why-did-you-update.ts │ │ │ └── use-client-source-id.ts │ │ ├── theme.ts │ │ ├── graph-ql │ │ │ └── index.ts │ │ └── reducer.ts │ ├── .npmignore │ ├── babel.config.js │ ├── jest.config.js │ ├── tsconfig.json │ ├── LICENSE │ ├── docs │ │ └── 2.dark-mode.md │ └── package.json ├── react-hooks │ ├── src │ │ ├── inbox │ │ │ ├── index.ts │ │ │ ├── actions │ │ │ │ ├── reset-last-fetched.ts │ │ │ │ ├── toggle-inbox.ts │ │ │ │ ├── init.ts │ │ │ │ ├── set-view.ts │ │ │ │ ├── add-tag.ts │ │ │ │ ├── unpin-message.ts │ │ │ │ ├── new-message.ts │ │ │ │ ├── mark-message-read.ts │ │ │ │ ├── remove-tag.ts │ │ │ │ ├── mark-message-opened.ts │ │ │ │ ├── mark-message-unread.ts │ │ │ │ ├── mark-message-archived.ts │ │ │ │ ├── fetch-unread-message-count.ts │ │ │ │ ├── mark-all-read.ts │ │ │ │ └── fetch-messages.ts │ │ │ ├── types.ts │ │ │ └── middleware.ts │ │ ├── index.ts │ │ └── preferences │ │ │ ├── use-preferences.ts │ │ │ ├── use-preferences-actions.ts │ │ │ └── reducer.ts │ ├── babel.config.js │ ├── jest.config.js │ ├── tsconfig.json │ ├── LICENSE │ ├── package.json │ └── docs │ │ └── 1.types.md └── transport │ ├── src │ ├── index.ts │ ├── types.ts │ ├── __mocks__ │ │ ├── index.ts │ │ └── ws.ts │ ├── courier │ │ └── types.ts │ └── base.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── babel.config.js │ └── package.json ├── commitlint.config.js ├── .prettierrc ├── .husky ├── pre-commit └── commit-msg ├── jest.config.js ├── nx.json ├── lerna.json ├── .github ├── pull_request_template.md └── workflows │ ├── test.yml │ ├── release.yml │ └── staging.yml ├── babel.config.react.js ├── tsconfig-base.json ├── LICENSE ├── .eslintrc.js └── jest.config.base.js /docs/intro.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18.16.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /packages/types/index.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/react-inbox-next/LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/react-toast/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/react-inbox-next/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/react-inbox-next/src/index.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/client-graphql/src/inbox/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/react-preferences/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./components"; 2 | -------------------------------------------------------------------------------- /packages/storybook/stories/style.css: -------------------------------------------------------------------------------- 1 | button { 2 | height: 45px; 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./types"; 2 | export * from "./lib"; 3 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/modal/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./modal"; 2 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ["@commitlint/config-conventional"] }; 2 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/color-pickers/index.tsx: -------------------------------------------------------------------------------- 1 | export * from "./medium"; 2 | -------------------------------------------------------------------------------- /packages/react-inbox/src/global.d.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom/extend-expect"; 2 | -------------------------------------------------------------------------------- /packages/react-toast/src/global.d.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom/extend-expect"; 2 | -------------------------------------------------------------------------------- /packages/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trycourier/courier-react/HEAD/packages/.DS_Store -------------------------------------------------------------------------------- /packages/react-brand-designer/src/brand-designer/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./brand-designer"; 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "arrowParens": "always" 5 | } -------------------------------------------------------------------------------- /packages/react-elements/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./components"; 2 | export * from "./types"; 3 | -------------------------------------------------------------------------------- /packages/components/src/components/Inbox.ts: -------------------------------------------------------------------------------- 1 | export { Inbox as default } from "@trycourier/react-inbox"; 2 | -------------------------------------------------------------------------------- /packages/components/src/components/Toast.ts: -------------------------------------------------------------------------------- 1 | export { Toast as default } from "@trycourier/react-toast"; 2 | -------------------------------------------------------------------------------- /packages/react-elements/.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | tsconfig.json 3 | jest.config.js 4 | __tests__ 5 | src 6 | -------------------------------------------------------------------------------- /packages/react-inbox/.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | tsconfig.json 3 | jest.config.js 4 | __tests__ 5 | src 6 | -------------------------------------------------------------------------------- /packages/react-toast/.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | tsconfig.json 3 | jest.config.js 4 | __tests__ 5 | src 6 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx pretty-quick --staged 5 | -------------------------------------------------------------------------------- /packages/react-inbox-next/.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | tsconfig.json 3 | jest.config.js 4 | __tests__ 5 | src 6 | -------------------------------------------------------------------------------- /packages/react-provider/src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export const COURIER_CLIENT_HEADER = "x-courier-client-key"; 2 | -------------------------------------------------------------------------------- /packages/components/src/components/Footer.ts: -------------------------------------------------------------------------------- 1 | export { Footer as default } from "@trycourier/react-preferences"; 2 | -------------------------------------------------------------------------------- /packages/components/src/components/Header.ts: -------------------------------------------------------------------------------- 1 | export { Header as default } from "@trycourier/react-preferences"; 2 | -------------------------------------------------------------------------------- /packages/react-brand-designer/.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | tsconfig.json 3 | jest.config.js 4 | __tests__ 5 | src 6 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit ${1} 5 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rootDir: ".", 3 | projects: ["/packages/*/jest.config.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/buttons/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./button"; 2 | export * from "./link-button"; 3 | -------------------------------------------------------------------------------- /packages/react-provider/.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | tsconfig.json 3 | jest.config.js 4 | __tests__ 5 | __mocks__ 6 | src 7 | -------------------------------------------------------------------------------- /packages/components/src/components/Preferences.ts: -------------------------------------------------------------------------------- 1 | export { PreferenceList as default } from "@trycourier/react-preferences"; 2 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/icons/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./courier"; 2 | export * from "./courier-text-logo"; 3 | -------------------------------------------------------------------------------- /packages/react-toast/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trycourier/courier-react/HEAD/packages/react-toast/src/.DS_Store -------------------------------------------------------------------------------- /packages/types/@types/css/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.css" { 2 | const value: string; 3 | export default value; 4 | } 5 | -------------------------------------------------------------------------------- /packages/types/@types/png/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.png" { 2 | const value: string; 3 | export default value; 4 | } 5 | -------------------------------------------------------------------------------- /packages/types/@types/md/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.md" { 2 | const buttonMd: string; 3 | export default buttonMd; 4 | } 5 | -------------------------------------------------------------------------------- /packages/components/src/components/UnsubscribePage.tsx: -------------------------------------------------------------------------------- 1 | export { UnsubscribePage as default } from "@trycourier/react-preferences"; 2 | -------------------------------------------------------------------------------- /packages/types/@types/jsonnet/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.jsonnet" { 2 | const value: string; 3 | export default value; 4 | } 5 | -------------------------------------------------------------------------------- /packages/react-inbox/__mocks__/fileMock.ts: -------------------------------------------------------------------------------- 1 | const content = "test"; 2 | export const ReactComponent = content; 3 | export default content; 4 | -------------------------------------------------------------------------------- /packages/types/@types/raw-loader/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "!raw-loader!*" { 2 | const text: string; 3 | export default text; 4 | } 5 | -------------------------------------------------------------------------------- /packages/react-brand-designer/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./brand-designer"; 2 | export * from "./clipboard-brand-designer"; 3 | export * from "./types"; 4 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/index.ts: -------------------------------------------------------------------------------- 1 | import { IInbox } from "./types"; 2 | export { default as useInbox } from "./use-inbox"; 3 | export { IInbox }; 4 | -------------------------------------------------------------------------------- /packages/react-preferences/src/components/DeliveryChannels.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | // TODO 4 | export const ChannelPreferences: React.FC = () => <>; 5 | -------------------------------------------------------------------------------- /packages/react-preferences/docs/example.com-preferences.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trycourier/courier-react/HEAD/packages/react-preferences/docs/example.com-preferences.png -------------------------------------------------------------------------------- /packages/react-provider/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useCourier } from "./use-courier"; 2 | export { default as useCourierActions } from "./use-courier-actions"; 3 | -------------------------------------------------------------------------------- /packages/react-inbox/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./components"; 2 | export * from "./hooks"; 3 | export * from "./types"; 4 | export { useInbox } from "@trycourier/react-hooks"; 5 | -------------------------------------------------------------------------------- /packages/types/@types/slate-soft-break/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "slate-soft-break" { 2 | import { Plugin } from "slate"; 3 | export default function SlatePlugin(): Plugin; 4 | } 5 | -------------------------------------------------------------------------------- /packages/types/@types/slate-soft-breaks/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "slate-soft-break" { 2 | import { Plugin } from "slate"; 3 | export default function SlatePlugin(): Plugin; 4 | } 5 | -------------------------------------------------------------------------------- /packages/react-inbox/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const MESSAGE_LABELS = { 2 | MARK_AS_READ: "Mark as Read", 3 | MARK_AS_UNREAD: "Mark as Unread", 4 | ARCHIVE_MESSAGE: "Archive", 5 | }; 6 | -------------------------------------------------------------------------------- /packages/react-elements/src/types.ts: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export type CourierElement> = React.FC< 4 | React.HTMLAttributes & T 5 | >; 6 | -------------------------------------------------------------------------------- /packages/react-hooks/babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const babelConfig = require("../../babel.config.react"); 3 | module.exports = babelConfig(__dirname); 4 | -------------------------------------------------------------------------------- /packages/react-inbox/babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const babelConfig = require("../../babel.config.react"); 3 | module.exports = babelConfig(__dirname); 4 | -------------------------------------------------------------------------------- /packages/react-toast/babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const babelConfig = require("../../babel.config.react"); 3 | module.exports = babelConfig(__dirname); 4 | -------------------------------------------------------------------------------- /packages/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trycourier/types", 3 | "private": true, 4 | "version": "7.4.0", 5 | "main": "index.d.ts", 6 | "types": "index.d.ts", 7 | "scripts": {} 8 | } 9 | -------------------------------------------------------------------------------- /packages/react-elements/babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const babelConfig = require("../../babel.config.react"); 3 | module.exports = babelConfig(__dirname); 4 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/icons/courier.tsx: -------------------------------------------------------------------------------- 1 | import CourierSvg from "./assets/courier.svg"; 2 | import { makeIcon } from "./make-icon"; 3 | 4 | export const Courier = makeIcon(CourierSvg); 5 | -------------------------------------------------------------------------------- /packages/react-inbox-next/babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const babelConfig = require("../../babel.config.react"); 3 | module.exports = babelConfig(__dirname); 4 | -------------------------------------------------------------------------------- /packages/react-preferences/babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const babelConfig = require("../../babel.config.react"); 3 | module.exports = babelConfig(__dirname); 4 | -------------------------------------------------------------------------------- /packages/react-provider/babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const babelConfig = require("../../babel.config.react"); 3 | module.exports = babelConfig(__dirname); 4 | -------------------------------------------------------------------------------- /packages/storybook/.storybook/manager.js: -------------------------------------------------------------------------------- 1 | // .storybook/manager.js 2 | 3 | import { addons } from "@storybook/addons"; 4 | import theme from "./theme"; 5 | 6 | addons.setConfig({ 7 | theme, 8 | }); 9 | -------------------------------------------------------------------------------- /packages/react-brand-designer/babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const babelConfig = require("../../babel.config.react"); 3 | module.exports = babelConfig(__dirname); 4 | -------------------------------------------------------------------------------- /packages/client-graphql/docs/inbox/0.overview.md: -------------------------------------------------------------------------------- 1 | ## Courier Inbox Graph 2 | 3 | > These APIs are only for the _Inbox_ channel inside Courier. If you are using "Courier Push", then you should be using _Messages_ Graph for the mean time. 4 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/buttons/types.ts: -------------------------------------------------------------------------------- 1 | export interface ButtonProps { 2 | size?: "xs" | "sm" | "md" | "lg"; 3 | // Color of the button 4 | color?: string; 5 | /** Defaults to white */ 6 | textColor?: string; 7 | } 8 | -------------------------------------------------------------------------------- /packages/react-preferences/src/components/SnoozePreference.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { PreferenceItemComponentFn } from "../types"; 3 | 4 | // TODO 5 | export const SnoozePreference: PreferenceItemComponentFn = () => <>; 6 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/icons/courier-text-logo.tsx: -------------------------------------------------------------------------------- 1 | import CourierTextLogoSvg from "./assets/courier-text-logo.svg"; 2 | import { makeIcon } from "./make-icon"; 3 | 4 | export const CourierTextLogo = makeIcon(CourierTextLogoSvg); 5 | -------------------------------------------------------------------------------- /packages/transport/src/index.ts: -------------------------------------------------------------------------------- 1 | import { TransportOptions } from "./courier/types"; 2 | 3 | export * from "./courier"; 4 | export * from "./base"; 5 | export * from "./types"; 6 | export * from "./ws"; 7 | 8 | export type { TransportOptions }; 9 | -------------------------------------------------------------------------------- /packages/core/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "nx/presets/npm.json", 3 | "tasksRunnerOptions": { 4 | "default": { 5 | "runner": "nx/tasks-runners/default", 6 | "options": { 7 | "cacheableOperations": ["build"] 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/buttons/button.tsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { genButtonStyles } from "./styles"; 3 | import { ButtonProps } from "./types"; 4 | 5 | export const Button = styled.button(genButtonStyles); 6 | -------------------------------------------------------------------------------- /packages/react-hooks/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/react-inbox/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/react-toast/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/transport/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/types/@types/react-fade-in/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-fade-in" { 2 | type FadeInProps = { 3 | children: React.ReactNode; 4 | }; 5 | 6 | const FadeIn: React.FunctionComponent; 7 | 8 | export default FadeIn; 9 | } 10 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "version": "independent", 4 | "npmClient": "yarn", 5 | "useNx": true, 6 | "useWorkspaces": true, 7 | "command": { 8 | "publish": { 9 | "scope": "@trycourier" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/client-graphql/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/react-brand-designer/src/brand-designer/default-theme.ts: -------------------------------------------------------------------------------- 1 | import { BrandDesignerTheme } from "~/types"; 2 | 3 | export const defaultBrandDesignerTheme: BrandDesignerTheme = { 4 | background: "#F9FAFB", 5 | fontFamily: "'Nunito Sans', sans-serif", 6 | }; 7 | -------------------------------------------------------------------------------- /packages/react-elements/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/buttons/link-button.tsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { genButtonStyles } from "./styles"; 3 | import { ButtonProps } from "./types"; 4 | 5 | export const LinkButton = styled.a(genButtonStyles); 6 | -------------------------------------------------------------------------------- /packages/react-inbox-next/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/react-provider/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/react-brand-designer/jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const jestConfigBase = require("../../jest.config.base"); 3 | const babelConfig = require("./babel.config.js"); 4 | 5 | module.exports = jestConfigBase(babelConfig); 6 | -------------------------------------------------------------------------------- /packages/react-inbox/src/assets/back.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/react-inbox/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { CourierProvider } from "@trycourier/react-provider"; 2 | export { default as Inbox } from "./Inbox"; 3 | export { default as Header } from "./Messages2.0/Header"; 4 | export { TextElement } from "./Messages2.0/styled"; 5 | -------------------------------------------------------------------------------- /packages/react-toast/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { IToastConfig } from "./types"; 2 | import Toast from "./components/Toast"; 3 | 4 | export { useToast } from "./hooks"; 5 | export { Toast }; 6 | export { ToastBody } from "./components"; 7 | export type ToastProps = IToastConfig; 8 | -------------------------------------------------------------------------------- /packages/react-toast/src/defaults.ts: -------------------------------------------------------------------------------- 1 | import { IToastConfig } from "./types"; 2 | 3 | export const defaultConfig: IToastConfig = { 4 | hideProgressBar: false, 5 | openLinksInNewTab: true, 6 | position: "top-right", 7 | theme: {}, 8 | transition: "slide", 9 | }; 10 | -------------------------------------------------------------------------------- /packages/types/@types/react-color-extractor/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-color-extractor" { 2 | interface ColorExtractorProp { 3 | children: JSX; 4 | getColors?: Function; 5 | } 6 | 7 | export const ColorExtractor: React.FunctionComponent; 8 | } 9 | -------------------------------------------------------------------------------- /packages/react-hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./inbox"; 2 | export { 3 | default as usePreferences, 4 | UsePreferences, 5 | } from "./preferences/use-preferences"; 6 | export { PreferenceSection } from "./preferences/types"; 7 | export { default as useTransport } from "./use-transport"; 8 | -------------------------------------------------------------------------------- /packages/react-preferences/docs/2.limitations.md: -------------------------------------------------------------------------------- 1 | # [Limitations](#limitations) 2 | 3 | This repository is not currently fully customizable; it has opinions on components (checkboxes and radio buttons), margins, paddings, font height, gaps, etc. It does adhere to configured Brands colors and logos. 4 | -------------------------------------------------------------------------------- /packages/react-toast/src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export const COURIER_CLIENT_HEADER = "x-courier-client-key"; 2 | 3 | export const themeDefaults = { 4 | colors: { 5 | primary: "#9121c2", 6 | }, 7 | inapp: { 8 | toast: { 9 | borderRadius: "6px", 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * as icons from "./icons"; 2 | export * from "./title"; 3 | export * from "./buttons"; 4 | export * from "./pretty-date"; 5 | export * from "./color-pickers"; 6 | export * from "./description"; 7 | export * from "./modal"; 8 | export * from "./input"; 9 | -------------------------------------------------------------------------------- /packages/react-inbox/src/assets/options.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/react-inbox/src/components/OptionsDropdown/styled.ts: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const OptionsIconButton = styled.button` 4 | outline: none; 5 | border: none; 6 | padding: 0; 7 | background: transparent; 8 | margin-top: 6px; 9 | padding: 0 12px; 10 | cursor: pointer; 11 | `; 12 | -------------------------------------------------------------------------------- /packages/types/@types/svg/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.svg" { 2 | export type SvgComponent = React.FunctionComponent<{ 3 | width?: string | number; 4 | height?: string | number; 5 | preserveAspectRatio?: string; 6 | viewBox?: string; 7 | }>; 8 | const Svg: SvgComponent; 9 | export default Svg; 10 | } 11 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/reset-last-fetched.ts: -------------------------------------------------------------------------------- 1 | export type ResetLastFetched = { 2 | type: "inbox/RESET_LAST_FETCHED"; 3 | }; 4 | 5 | export const INBOX_RESET_LAST_FETCHED = "inbox/RESET_LAST_FETCHED"; 6 | 7 | export const resetLastFetched = (): ResetLastFetched => ({ 8 | type: INBOX_RESET_LAST_FETCHED, 9 | }); 10 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/storybook/stories/elements/title.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactMarkdown from "react-markdown"; 3 | import titleMd from "@trycourier/react-elements/docs/title.md"; 4 | 5 | export default { 6 | title: "Elements/Title", 7 | }; 8 | 9 | export const Title = () => {titleMd}; 10 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/toggle-inbox.ts: -------------------------------------------------------------------------------- 1 | export type ToggleInbox = { 2 | type: "inbox/TOGGLE_INBOX"; 3 | payload?: boolean; 4 | }; 5 | 6 | export const INBOX_TOGGLE = "inbox/TOGGLE_INBOX"; 7 | 8 | export const toggleInbox = (isOpen?: boolean): ToggleInbox => ({ 9 | type: INBOX_TOGGLE, 10 | payload: isOpen, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/transport/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ErrorEvent } from "reconnecting-websocket"; 2 | export type ErrorEventHandler = (event: ErrorEvent) => void; 3 | 4 | export type WSOptions = { 5 | url?: string; 6 | onError?: ErrorEventHandler; 7 | onClose?: () => void; 8 | onReconnect?: () => void; 9 | connectionTimeout?: number; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/transport/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/client-graphql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/storybook/stories/elements/index.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactMarkdown from "react-markdown"; 3 | import overviewMd from "@trycourier/react-elements/docs/0.overview.md"; 4 | 5 | export default { 6 | title: "Elements", 7 | }; 8 | 9 | export const Elements = () => {overviewMd}; 10 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/description.tsx: -------------------------------------------------------------------------------- 1 | import styled, { CSSObject } from "styled-components"; 2 | 3 | export const Description = styled.p( 4 | (): CSSObject => ({ 5 | fontFamily: "'Nunito Sans', sans-serif", 6 | fontWeight: 400, 7 | fontSize: "10px", 8 | color: "#79849A", 9 | margin: "6px 0 0 0", 10 | }) 11 | ); 12 | -------------------------------------------------------------------------------- /packages/types/@types/tailwind.macro/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "tailwind.macro" { 2 | import tw from "tailwind.macro"; 3 | export default function tw( 4 | templateString: TemplateStringsArray 5 | ): Interpolation< 6 | ThemedStyledProps< 7 | Pick, HTMLDivElement>> 8 | > 9 | >; 10 | } 11 | -------------------------------------------------------------------------------- /packages/components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.tsx", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.tsx", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-inbox/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.tsx", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-preferences/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { UnsubscribePage } from "./UnsubscribePage"; 2 | export { PreferenceTemplate } from "./PreferenceTemplate"; 3 | export { PreferenceList } from "./PreferenceList"; 4 | export { PreferencesV4, PreferenceSections } from "./PreferencesV4"; 5 | export { Footer } from "./Footer"; 6 | export { Header } from "./Header"; 7 | -------------------------------------------------------------------------------- /packages/react-toast/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.tsx", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-inbox-next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.tsx", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-provider/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.tsx", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-brand-designer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.tsx", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-elements/docs/0.overview.md: -------------------------------------------------------------------------------- 1 | ## React Elements 2 | 3 | Courier React Elements is a package of bite sized components that are shared between our 4 | larger components like Inbox and Toast. 5 | 6 | This package includes highly reusable components such as buttons, icons, and modals. 7 | 8 | Caution: This package is not yet stable. Interfaces are subject to change. 9 | -------------------------------------------------------------------------------- /packages/react-preferences/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": ["../types/@types/*/index.d.ts", "./src/**/*.tsx", "./src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-provider/src/hooks/use-courier.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { CourierContext } from "../"; 3 | import { ICourierContext } from "../types"; 4 | 5 | function useCourier(): ICourierContext & T { 6 | const context = useContext(CourierContext) as ICourierContext & T; 7 | return context; 8 | } 9 | 10 | export default useCourier; 11 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/init.ts: -------------------------------------------------------------------------------- 1 | import { IInbox } from "../types"; 2 | 3 | export type InboxInit = { 4 | type: "inbox/INIT"; 5 | payload: T; 6 | }; 7 | 8 | export const INBOX_INIT = "inbox/INIT"; 9 | 10 | export function initInbox(payload: T): InboxInit { 11 | return { 12 | type: INBOX_INIT, 13 | payload, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /packages/transport/src/__mocks__/index.ts: -------------------------------------------------------------------------------- 1 | const connectMock = jest.fn(); 2 | const renewSessionMock = jest.fn(); 3 | 4 | export const CourierTransport = jest.fn().mockImplementation(() => { 5 | return { 6 | connect: connectMock, 7 | renewSession: renewSessionMock, 8 | }; 9 | }); 10 | 11 | const transportMock = jest.fn(); 12 | export const Transport = transportMock; 13 | -------------------------------------------------------------------------------- /packages/transport/src/__mocks__/ws.ts: -------------------------------------------------------------------------------- 1 | export const mockConnect = jest.fn(); 2 | export const mockSend = jest.fn(); 3 | export const mockRenewSession = jest.fn(); 4 | 5 | const mock = jest.fn().mockImplementation(() => { 6 | return { 7 | connect: mockConnect, 8 | send: mockSend, 9 | renewSession: mockRenewSession, 10 | }; 11 | }); 12 | 13 | export const WS = mock; 14 | -------------------------------------------------------------------------------- /packages/react-elements/docs/title.md: -------------------------------------------------------------------------------- 1 | ### [Title](#title) 2 | 3 | A simple title. Uses `

` as its root element. 4 | 5 | Usage: 6 | 7 | ```tsx 8 | import { Title } from "react-elements"; 9 | 10 | interface TitleProps { 11 | children: React.ReactNode; 12 | /** CSS Overrides to apply to the title*/ 13 | css?: CSSObject; 14 | } 15 | 16 | Hello World; 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/react-toast/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { Bounce, Slide, Zoom } from "react-toastify"; 2 | 3 | export function getTransition(type?: string) { 4 | switch (type) { 5 | case "slide": 6 | return Slide; 7 | case "zoom": 8 | return Zoom; 9 | case "bounce": 10 | return Bounce; 11 | 12 | default: { 13 | return Slide; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/input.tsx: -------------------------------------------------------------------------------- 1 | import styled, { CSSObject } from "styled-components"; 2 | 3 | export const Input = styled.input( 4 | (): CSSObject => ({ 5 | width: "100%", 6 | boxSizing: "border-box", 7 | padding: "0.75rem", 8 | borderRadius: "0.25rem", 9 | border: "none", 10 | "&:focus": { 11 | outline: "none", 12 | }, 13 | }) 14 | ); 15 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/set-view.ts: -------------------------------------------------------------------------------- 1 | type InboxView = string | "preferences"; 2 | 3 | export type InboxSetView = { 4 | type: "inbox/SET_VIEW"; 5 | payload: InboxView; 6 | }; 7 | 8 | export const INBOX_SET_VIEW = "inbox/SET_VIEW"; 9 | 10 | export const setView = (view: string | "preferences"): InboxSetView => ({ 11 | type: INBOX_SET_VIEW, 12 | payload: view, 13 | }); 14 | -------------------------------------------------------------------------------- /packages/types/@types/better-react-spinkit/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "better-react-spinkit" { 2 | type SpinnerProps = { 3 | className?: string; 4 | color?: string; 5 | duration?: string; 6 | scaleEnd?: number; 7 | scaleStart?: number; 8 | size?: number; 9 | }; 10 | 11 | const Pulse: React.FunctionComponent; 12 | 13 | export { Pulse }; 14 | } 15 | -------------------------------------------------------------------------------- /packages/types/@types/react-top-loading-bar/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-top-loading-bar" { 2 | type LoadingBarProps = { 3 | className?: string; 4 | onRef: (ref: React.RefObject) => void; 5 | color: string; 6 | height: number; 7 | }; 8 | 9 | const ReactTopLoadingBar: React.FunctionComponent; 10 | 11 | export default ReactTopLoadingBar; 12 | } 13 | -------------------------------------------------------------------------------- /packages/react-elements/src/components/icons/types.ts: -------------------------------------------------------------------------------- 1 | import { CSSObject } from "styled-components"; 2 | 3 | export interface IconProps { 4 | /** Defaults to 100% of parent. */ 5 | size?: "xs" | "sm" | "md" | "lg" | number; 6 | color?: string; 7 | /** CSS Overrides of the SVG container */ 8 | css?: CSSObject; 9 | /** CSS Overrides of the SVG tag */ 10 | svgCSS?: CSSObject; 11 | } 12 | -------------------------------------------------------------------------------- /packages/react-provider/src/theme.ts: -------------------------------------------------------------------------------- 1 | export const lightVariables = { 2 | background: "#f2f6f9", 3 | textColor: "#1c273a", 4 | titleColor: "#1c273a", 5 | structure: "#DEE8F0", 6 | icon: "#566074", 7 | }; 8 | 9 | export const darkVariables = { 10 | background: "#262A34", 11 | textColor: "#C9C8E1", 12 | titleColor: "white", 13 | structure: "#4F4D67", 14 | icon: "#8786A9", 15 | }; 16 | -------------------------------------------------------------------------------- /packages/storybook/.storybook/theme.ts: -------------------------------------------------------------------------------- 1 | import { create } from "@storybook/theming"; 2 | 3 | export default create({ 4 | base: "light", 5 | brandTitle: "Courier In-App", 6 | brandUrl: "https://app.courier.com", 7 | brandImage: 8 | "https://d33wubrfki0l68.cloudfront.net/ca2747f11cc64d0e424e27b4a804b9d981b22453/9ab46/_next/static/images/logo@2x-5d5af82635bfdd3ad24e54f9eb364097.png", 9 | }); 10 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | [Pull Request Description Here] 4 | 5 | ## Type of change 6 | 7 | - [ ] Bug fix (non-breaking change that fixes an issue) 8 | - [ ] New feature (non-breaking change that adds functionality) 9 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 10 | 11 | ## Related issues 12 | 13 | > `Fix [#1]()` 14 | -------------------------------------------------------------------------------- /packages/storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./stories", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./stories/*"] 9 | } 10 | }, 11 | "include": [ 12 | "../types/@types/*/index.d.ts", 13 | "./stories/**/*.tsx", 14 | "./stories/**/*.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/client-graphql/src/index.ts: -------------------------------------------------------------------------------- 1 | export { createCourierClient } from "./client"; 2 | export { default as Banner } from "./banner"; 3 | export { default as Brands } from "./brands"; 4 | export { default as Events } from "./events"; 5 | export { default as Inbox, IGetInboxMessagesParams } from "./inbox"; 6 | export { 7 | default as Preferences, 8 | UpdateRecipientPreferencesPayload, 9 | } from "./preferences"; 10 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/add-tag.ts: -------------------------------------------------------------------------------- 1 | export type AddTag = { 2 | type: "inbox/ADD_TAG"; 3 | payload: { 4 | tag: string; 5 | messageId: string; 6 | }; 7 | }; 8 | 9 | export const INBOX_ADD_TAG = "inbox/ADD_TAG"; 10 | 11 | export const addTag = (messageId: string, tag: string): AddTag => ({ 12 | type: INBOX_ADD_TAG, 13 | payload: { 14 | tag, 15 | messageId, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/unpin-message.ts: -------------------------------------------------------------------------------- 1 | export type UnpinMessage = { 2 | type: "inbox/UNPIN_MESSAGE"; 3 | payload: { 4 | messageId: string; 5 | }; 6 | }; 7 | 8 | export const INBOX_UNPIN_MESSAGE = "inbox/UNPIN_MESSAGE"; 9 | 10 | export const unpinMessage = (messageId: string): UnpinMessage => ({ 11 | type: INBOX_UNPIN_MESSAGE, 12 | payload: { 13 | messageId, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /packages/react-inbox/src/components/Messages2.0/types.ts: -------------------------------------------------------------------------------- 1 | import { IInboxMessagePreview } from "@trycourier/core"; 2 | import { InboxProps } from "~/types"; 3 | 4 | export type InboxView = "settings" | "messages"; 5 | export interface IHeaderProps { 6 | labels: InboxProps["labels"]; 7 | markAllAsRead?: () => any; 8 | messages: IInboxMessagePreview[]; 9 | title?: string; 10 | unreadMessageCount?: number; 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export const getDateDiff = (date?: number) => { 2 | if (!date) { 3 | return; 4 | } 5 | 6 | const now = new Date().getTime(); 7 | const dateDiff = now - date; 8 | 9 | // if datediff is 0, return 1 so we can do "!datediff" 10 | return Math.max(dateDiff, 1); 11 | }; 12 | 13 | export const defaultMarkdownOptions = { 14 | overrides: { 15 | iframe: () => null, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/new-message.ts: -------------------------------------------------------------------------------- 1 | import { IInboxMessagePreview } from "@trycourier/core"; 2 | 3 | export type NewMessage = { 4 | type: "inbox/NEW_MESSAGE"; 5 | payload: IInboxMessagePreview; 6 | }; 7 | 8 | export const INBOX_NEW_MESSAGE = "inbox/NEW_MESSAGE"; 9 | 10 | export const newMessage = (message: IInboxMessagePreview): NewMessage => ({ 11 | type: INBOX_NEW_MESSAGE, 12 | payload: message, 13 | }); 14 | -------------------------------------------------------------------------------- /packages/react-elements/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "declarationDir": "./typings", 7 | "paths": { 8 | "~/*": ["./src/*"] 9 | } 10 | }, 11 | "include": [ 12 | "../types/@types/*/index.d.ts", 13 | "./src/**/*.tsx", 14 | "./src/**/*.ts", 15 | "src/components/color-pickers" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/mark-message-read.ts: -------------------------------------------------------------------------------- 1 | export type MarkMessageRead = { 2 | type: "inbox/MARK_MESSAGE_READ"; 3 | payload: { 4 | messageId: string; 5 | }; 6 | }; 7 | 8 | export const INBOX_MARK_MESSAGE_READ = "inbox/MARK_MESSAGE_READ"; 9 | 10 | export const markMessageRead = (messageId: string): MarkMessageRead => ({ 11 | type: INBOX_MARK_MESSAGE_READ, 12 | payload: { 13 | messageId, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/remove-tag.ts: -------------------------------------------------------------------------------- 1 | export type RemoveTag = { 2 | type: "inbox/REMOVE_TAG"; 3 | payload: { 4 | tag: string; 5 | messageId: string; 6 | }; 7 | }; 8 | 9 | export const INBOX_REMOVE_TAG = "inbox/REMOVE_TAG"; 10 | 11 | export const removeTag = (messageId: string, tag: string): RemoveTag => ({ 12 | type: INBOX_REMOVE_TAG, 13 | payload: { 14 | tag, 15 | messageId, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/react-toast/src/reducer.ts: -------------------------------------------------------------------------------- 1 | import { IToastConfig } from "./types"; 2 | 3 | interface ToastState { 4 | config: IToastConfig; 5 | } 6 | 7 | export default (state: ToastState, action) => { 8 | switch (action.type) { 9 | case "toast/INIT": { 10 | return { 11 | ...state, 12 | config: action.payload.config, 13 | toast: action.payload.toast, 14 | }; 15 | } 16 | } 17 | 18 | return state; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/react-toast/src/hooks/types.ts: -------------------------------------------------------------------------------- 1 | import { IInboxMessagePreview } from "@trycourier/core"; 2 | import { IToastConfig } from "../types"; 3 | 4 | export type ToastCaller = ( 5 | message: 6 | | string 7 | | IInboxMessagePreview 8 | | { 9 | preview?: string; 10 | title?: string; 11 | } 12 | ) => void; 13 | export type UseToast = () => [ 14 | ToastCaller, 15 | { config: IToastConfig; clientKey?: string } 16 | ]; 17 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/mark-message-opened.ts: -------------------------------------------------------------------------------- 1 | export type MarkMessageOpened = { 2 | type: "inbox/MARK_MESSAGE_OPENED"; 3 | payload: { 4 | messageId: string; 5 | }; 6 | }; 7 | 8 | export const INBOX_MARK_MESSAGE_OPENED = "inbox/MARK_MESSAGE_OPENED"; 9 | 10 | export const markMessageOpened = (messageId: string): MarkMessageOpened => ({ 11 | type: INBOX_MARK_MESSAGE_OPENED, 12 | payload: { 13 | messageId, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/mark-message-unread.ts: -------------------------------------------------------------------------------- 1 | export type MarkMessageUnread = { 2 | type: "inbox/MARK_MESSAGE_UNREAD"; 3 | payload: { 4 | messageId: string; 5 | }; 6 | }; 7 | 8 | export const INBOX_MARK_MESSAGE_UNREAD = "inbox/MARK_MESSAGE_UNREAD"; 9 | 10 | export const markMessageUnread = (messageId: string): MarkMessageUnread => ({ 11 | type: INBOX_MARK_MESSAGE_UNREAD, 12 | payload: { 13 | messageId, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /packages/client-graphql/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sourceType: "unambiguous", 3 | plugins: [ 4 | "@babel/transform-runtime", 5 | "transform-inline-environment-variables", 6 | process.env.NODE_ENV !== "test" && [ 7 | "babel-plugin-root-import", 8 | { 9 | rootPathSuffix: "./src", 10 | rootPathPrefix: "~/", 11 | }, 12 | ], 13 | ].filter(Boolean), 14 | presets: ["@babel/preset-typescript", "@babel/preset-env"], 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react-inbox/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useClickOutside } from "./use-click-outside"; 2 | export { default as useWindowSize } from "./use-window-size"; 3 | export { default as useEventListener } from "./use-event-listener"; 4 | export { default as useLocalStorageMessages } from "./use-local-storage-messages"; 5 | export { default as useMessageOptions } from "./use-message-options"; 6 | export { default as useHover } from "./use-hover"; 7 | export { useOnScreen } from "./use-on-screen"; 8 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/actions/mark-message-archived.ts: -------------------------------------------------------------------------------- 1 | export type MarkMessageArchived = { 2 | type: "inbox/MARK_MESSAGE_ARCHIVED"; 3 | payload: { 4 | messageId: string; 5 | }; 6 | }; 7 | 8 | export const INBOX_MARK_MESSAGE_ARCHIVED = "inbox/MARK_MESSAGE_ARCHIVED"; 9 | 10 | export const markMessageArchived = ( 11 | messageId: string 12 | ): MarkMessageArchived => ({ 13 | type: INBOX_MARK_MESSAGE_ARCHIVED, 14 | payload: { 15 | messageId, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/react-preferences/src/assets/social-icons/icon-social-facebook.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/types/@types/react-table/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-table" { 2 | interface UseTableProps { 3 | data: any[]; 4 | columns: any[]; 5 | } 6 | 7 | interface UsePluginProps { 8 | hooks: any; 9 | } 10 | 11 | type plugin = (hooks: any) => void; 12 | 13 | export function useTable(UseTableProps, ...plugin); 14 | export function useSortBy(UsePluginProps); 15 | export function useFilters(UsePluginProps); 16 | export function useRowState(UsePluginProps); 17 | } 18 | -------------------------------------------------------------------------------- /packages/transport/src/courier/types.ts: -------------------------------------------------------------------------------- 1 | import { WSOptions } from "~/types"; 2 | 3 | export interface IBaseOptions { 4 | tenantId?: string; 5 | clientSourceId?: string; 6 | wsOptions?: WSOptions; 7 | } 8 | export interface IClientKeyOptions extends IBaseOptions { 9 | clientKey: string; 10 | userSignature?: string; 11 | } 12 | 13 | export interface IJWTOptions extends IBaseOptions { 14 | authorization: string; 15 | } 16 | 17 | export type TransportOptions = IClientKeyOptions | IJWTOptions; 18 | -------------------------------------------------------------------------------- /packages/core/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sourceType: "unambiguous", 3 | plugins: [ 4 | "@babel/transform-runtime", 5 | "transform-inline-environment-variables", 6 | "transform-class-properties", 7 | process.env.NODE_ENV !== "test" && [ 8 | "babel-plugin-root-import", 9 | { 10 | rootPathSuffix: "./src", 11 | rootPathPrefix: "~/", 12 | }, 13 | ], 14 | ].filter(Boolean), 15 | presets: ["@babel/preset-typescript", "@babel/preset-env"], 16 | }; 17 | -------------------------------------------------------------------------------- /packages/transport/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sourceType: "unambiguous", 3 | plugins: [ 4 | "@babel/transform-runtime", 5 | "transform-inline-environment-variables", 6 | "transform-class-properties", 7 | process.env.NODE_ENV !== "test" && [ 8 | "babel-plugin-root-import", 9 | { 10 | rootPathSuffix: "./src", 11 | rootPathPrefix: "~/", 12 | }, 13 | ], 14 | ].filter(Boolean), 15 | presets: ["@babel/preset-typescript", "@babel/preset-env"], 16 | }; 17 | -------------------------------------------------------------------------------- /packages/components/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sourceType: "unambiguous", 3 | plugins: [ 4 | "@babel/transform-runtime", 5 | "transform-inline-environment-variables", 6 | process.env.NODE_ENV !== "test" && [ 7 | "babel-plugin-root-import", 8 | { 9 | rootPathSuffix: "./src", 10 | rootPathPrefix: "~/", 11 | }, 12 | ], 13 | ].filter(Boolean), 14 | presets: [ 15 | "@babel/preset-typescript", 16 | "@babel/preset-env", 17 | "@babel/preset-react", 18 | ], 19 | }; 20 | -------------------------------------------------------------------------------- /packages/storybook/stories/toast/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/react-preferences/src/assets/checkmark-small.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/react-elements/docs/button.md: -------------------------------------------------------------------------------- 1 | ### [Button](#button) 2 | 3 | A simple button. Uses ` 17 | 18 | {linkButtonMd} 19 | Example 20 | Button 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /packages/storybook/stories/inbox/custom-header.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Header } from "@trycourier/react-inbox"; 3 | 4 | const props = { 5 | isOpen: true, 6 | theme: { 7 | header: { 8 | height: 0, 9 | paddingTop: 36, 10 | }, 11 | }, 12 | renderHeader: (props) => { 13 | return ( 14 | <> 15 |
16 |
24 | Hello World 25 |
26 | 27 | ); 28 | }, 29 | }; 30 | 31 | export default props; 32 | -------------------------------------------------------------------------------- /babel.config.react.js: -------------------------------------------------------------------------------- 1 | module.exports = (root) => ({ 2 | sourceType: "unambiguous", 3 | plugins: [ 4 | "inline-react-svg", 5 | "@babel/transform-runtime", 6 | "babel-plugin-styled-components", 7 | "transform-inline-environment-variables", 8 | "transform-class-properties", 9 | [ 10 | "babel-plugin-inline-import", 11 | { 12 | extensions: [".css"], 13 | }, 14 | ], 15 | [ 16 | "babel-plugin-root-import", 17 | { 18 | root, 19 | rootPathSuffix: "./src", 20 | rootPathPrefix: "~/", 21 | }, 22 | ], 23 | ].filter(Boolean), 24 | presets: [ 25 | "@babel/preset-typescript", 26 | "@babel/preset-env", 27 | "@babel/preset-react", 28 | ], 29 | }); 30 | -------------------------------------------------------------------------------- /packages/react-hooks/src/inbox/types.ts: -------------------------------------------------------------------------------- 1 | import { IGetInboxMessagesParams } from "@trycourier/client-graphql"; 2 | import { Brand, IInboxMessagePreview } from "@trycourier/core"; 3 | import { OnEvent } from "@trycourier/react-provider"; 4 | export interface IInbox { 5 | brand?: Brand; 6 | from?: number; 7 | isLoading?: boolean; 8 | isOpen?: boolean; 9 | lastMarkedAllRead?: number; 10 | lastMessagesFetched?: number; 11 | messages?: Array; 12 | onEvent?: OnEvent; 13 | pinned?: Array; 14 | recentlyArchiveMessageIds?: Array; 15 | searchParams?: IGetInboxMessagesParams; 16 | startCursor?: string; 17 | tenantId?: string; 18 | unreadMessageCount?: number; 19 | view?: string | "preferences"; 20 | } 21 | -------------------------------------------------------------------------------- /packages/storybook/stories/toast/styled.ts: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const Button = styled.button` 4 | outline: none; 5 | border: none; 6 | border-radius: 5px; 7 | height: 50px; 8 | width: 200px; 9 | background-color: black; 10 | color: white; 11 | font-size: 20px; 12 | font-family: Verdana; 13 | cursor: pointer; 14 | `; 15 | 16 | export const Input = styled.input` 17 | border: none; 18 | outline: none; 19 | background-color: lightgray; 20 | border-radius: 4px; 21 | height: 45px; 22 | width: calc(200px - 20px); 23 | margin: 10px 0; 24 | padding: 0 10px; 25 | font-size: 14px; 26 | `; 27 | 28 | export const Label = styled.div` 29 | font-size: 14px; 30 | color: black; 31 | font-family: Verdana; 32 | `; 33 | -------------------------------------------------------------------------------- /packages/react-inbox/src/assets/icon-settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/transport/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trycourier/transport", 3 | "version": "7.4.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "types": "typings/index.d.ts", 7 | "scripts": { 8 | "babel": "babel src -d dist --extensions \".ts\" --ignore \"src/**/__tests__/**\"", 9 | "build:watch": "yarn babel --watch", 10 | "build": "rimraf dist && yarn babel", 11 | "clean": "rimraf dist && rimraf typings", 12 | "type-check": "tsc --noEmit", 13 | "types": "tsc --emitDeclarationOnly" 14 | }, 15 | "license": "ISC", 16 | "dependencies": { 17 | "@trycourier/core": "^7.4.0", 18 | "jwt-decode": "^4.0.0", 19 | "reconnecting-websocket": "^4.4.0", 20 | "rimraf": "^5.0.0" 21 | }, 22 | "files": [ 23 | "dist/", 24 | "typings/" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /packages/storybook/.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: [ 3 | "../stories/*.stories.@(ts|tsx|js|jsx|mdx)", 4 | "../stories/*/*.stories.@(ts|tsx|js|jsx|mdx)", 5 | ], 6 | addons: [ 7 | "@storybook/addon-a11y", 8 | "@storybook/addon-essentials", 9 | "@storybook/addon-links", 10 | ], 11 | webpackFinal: async (config) => { 12 | config.module.rules.push({ 13 | test: /\.mjs$/, 14 | include: /node_modules/, 15 | type: "javascript/auto", 16 | }); 17 | return config; 18 | }, 19 | env: (config) => ({ 20 | ...config, 21 | CLIENT_KEY: process.env.CLIENT_KEY, 22 | USER_ID: process.env.USER_ID, 23 | API_URL: process.env.API_URL, 24 | WS_URL: process.env.WS_URL, 25 | INBOX_API_URL: process.env.INBOX_API_URL, 26 | }), 27 | }; 28 | -------------------------------------------------------------------------------- /packages/react-preferences/src/assets/social-icons/icon-social-twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/react-inbox/src/components/Inbox/LazyTippy.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import Tippy, { TippyProps } from "@tippyjs/react"; 3 | 4 | /* 5 | https://github.com/atomiks/tippyjs-react/issues/288 6 | found here: https://gist.github.com/atomiks/520f4b0c7b537202a23a3059d4eec908 7 | */ 8 | const LazyTippy: React.FunctionComponent = (props) => { 9 | const [mounted, setMounted] = useState(false); 10 | 11 | const lazyPlugin = { 12 | fn: () => ({ 13 | onMount: () => setMounted(true), 14 | }), 15 | }; 16 | 17 | const computedProps = { ...props }; 18 | 19 | computedProps.plugins = [lazyPlugin, ...(props.plugins || [])]; 20 | computedProps.content = mounted ? props.content : ""; 21 | return ; 22 | }; 23 | 24 | export default LazyTippy; 25 | -------------------------------------------------------------------------------- /packages/react-inbox/src/hooks/use-click-outside.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | export const useClickOutside = ( 4 | ref: React.RefObject, 5 | handler: EventListener 6 | ): void => { 7 | useEffect(() => { 8 | const listener: EventListener = (event) => { 9 | // Do nothing if clicking ref's element or descendent elements 10 | if (!ref.current || ref.current.contains(event.target as Node)) { 11 | return; 12 | } 13 | handler(event); 14 | }; 15 | document.addEventListener("mousedown", listener); 16 | document.addEventListener("touchstart", listener); 17 | return () => { 18 | document.removeEventListener("mousedown", listener); 19 | document.removeEventListener("touchstart", listener); 20 | }; 21 | }, [ref, handler]); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/react-hooks/src/preferences/use-preferences.ts: -------------------------------------------------------------------------------- 1 | import { useCourier, registerReducer } from "@trycourier/react-provider"; 2 | import { useEffect } from "react"; 3 | import reducer from "./reducer"; 4 | 5 | import usePreferencesActions, { 6 | UsePreferenceActions, 7 | } from "./use-preferences-actions"; 8 | import { PreferenceState } from "./types"; 9 | 10 | export type UsePreferences = PreferenceState & UsePreferenceActions; 11 | 12 | const usePreferences = (): UsePreferences => { 13 | const { preferences } = 14 | useCourier<{ 15 | preferences: PreferenceState; 16 | }>(); 17 | 18 | const actions = usePreferencesActions(); 19 | 20 | useEffect(() => { 21 | registerReducer("preferences", reducer); 22 | }, []); 23 | 24 | return { ...preferences, ...actions }; 25 | }; 26 | 27 | export default usePreferences; 28 | -------------------------------------------------------------------------------- /packages/react-inbox/src/hooks/use-on-screen.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | export const useOnScreen = (ref, options = {}) => { 4 | const [isIntersecting, setIsIntersecting] = useState(false); 5 | useEffect(() => { 6 | if (typeof IntersectionObserver === "undefined") { 7 | return; 8 | } 9 | const observer = new IntersectionObserver( 10 | ([entry]) => { 11 | setIsIntersecting(entry.isIntersecting); 12 | }, 13 | { 14 | rootMargin: "0px", 15 | ...options, 16 | } 17 | ); 18 | if (ref.current) { 19 | observer.observe(ref.current); 20 | } 21 | return () => { 22 | if (!ref.current) { 23 | return; 24 | } 25 | 26 | observer.unobserve(ref.current); 27 | }; 28 | }, []); 29 | return isIntersecting; 30 | }; 31 | -------------------------------------------------------------------------------- /packages/client-graphql/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trycourier/client-graphql", 3 | "version": "7.4.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "types": "typings/index.d.ts", 7 | "scripts": { 8 | "babel": "babel src -d dist --extensions \".ts\" --ignore \"src/**/__tests__/**\"", 9 | "build:watch": "yarn babel --watch", 10 | "build": "rimraf dist && yarn babel", 11 | "clean": "rimraf dist && rimraf typings", 12 | "test": "jest -c jest.config.js --runInBand", 13 | "type-check": "tsc --noEmit", 14 | "types": "tsc --emitDeclarationOnly" 15 | }, 16 | "license": "ISC", 17 | "dependencies": { 18 | "graphql": "^15.5.0", 19 | "isomorphic-fetch": "^3.0.0", 20 | "rimraf": "^5.0.0", 21 | "urql": "^2.0.1" 22 | }, 23 | "files": [ 24 | "dist/", 25 | "typings/" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /packages/react-provider/src/hooks/use-is-online.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | const useIsOnline = (): boolean | undefined => { 4 | if (typeof window === "undefined" || typeof navigator === "undefined") { 5 | return; 6 | } 7 | 8 | const [isOnline, setOnlineStatus] = useState(window.navigator.onLine); 9 | 10 | useEffect(() => { 11 | const toggleOnlineStatus = () => setOnlineStatus(window.navigator.onLine); 12 | 13 | window.addEventListener("online", toggleOnlineStatus); 14 | window.addEventListener("offline", toggleOnlineStatus); 15 | 16 | return () => { 17 | window.removeEventListener("online", toggleOnlineStatus); 18 | window.removeEventListener("offline", toggleOnlineStatus); 19 | }; 20 | }, [isOnline]); 21 | 22 | return isOnline; 23 | }; 24 | 25 | export { useIsOnline }; 26 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - run: echo "::set-output name=dir::$(yarn cache dir)" 10 | id: yarn-cache-dir-path 11 | - uses: actions/cache@v4 12 | id: yarn-cache 13 | with: 14 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 15 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 16 | restore-keys: | 17 | ${{ runner.os }}-yarn- 18 | - uses: actions/checkout@v2 19 | - uses: actions/setup-node@v2 20 | with: 21 | node-version: "18.X" 22 | - run: yarn 23 | - name: Typecheck 24 | run: yarn types 25 | - name: Test 26 | run: yarn test 27 | - uses: codecov/codecov-action@v1 28 | with: 29 | token: ${{ secrets.CODECOV_TOKEN }} 30 | -------------------------------------------------------------------------------- /packages/storybook/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { Normalize } from "styled-normalize"; 4 | import { addDecorator } from "@storybook/react"; 5 | import { INITIAL_VIEWPORTS } from "@storybook/addon-viewport"; 6 | import githubCss from "./github.css"; 7 | import styled from "styled-components"; 8 | 9 | const Styled = styled.div` 10 | ${githubCss}; 11 | width: 1000px; 12 | 13 | img { 14 | max-width: 100%; 15 | } 16 | `; 17 | 18 | addDecorator((storyFn) => 19 | React.createElement(() => ( 20 | 21 | 22 |
{storyFn()}
23 |
24 | )) 25 | ); 26 | 27 | export const parameters = { 28 | options: { 29 | storySort: { 30 | order: ["Introduction", "Getting Started", "Authentication"], 31 | }, 32 | }, 33 | viewport: { 34 | viewports: INITIAL_VIEWPORTS, 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /tsconfig-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "allowJs": false, 8 | "allowSyntheticDefaultImports": true, 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "lib": ["dom", "esnext"], 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "noImplicitAny": false, 17 | "preserveConstEnums": true, 18 | "pretty": true, 19 | "removeComments": false, 20 | "resolveJsonModule": true, 21 | "skipLibCheck": true, 22 | "jsx": "react", 23 | "checkJs": false 24 | }, 25 | "exclude": [ 26 | "**/__tests__/**", 27 | "**/*.spec.ts", 28 | "**/*.story.ts", 29 | "**/dist/**", 30 | "**/typings/**", 31 | "node_modules" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/react-preferences/docs/1.easy-usage.md: -------------------------------------------------------------------------------- 1 | # [Easy Usage](#easy-usage) 2 | 3 | ```jsx 4 | import React from "react"; 5 | import { Footer, Header, PreferencesV4 } from "@trycourier/react-preferences"; 6 | import { CourierProvider } from "@trycourier/react-provider"; 7 | 8 | const PreferencePage: React.FunctionComponent<{ 9 | tenantId?: string, 10 | draft?: boolean, 11 | }> = ({ tenantId, draft = false }) => { 12 | return ( 13 | 18 |
19 | 20 |