Skip to content

Commit

Permalink
/integrations facelift (calcom#858)
Browse files Browse the repository at this point in the history
  • Loading branch information
KATT authored Oct 12, 2021
1 parent 7dc4a55 commit c3dc186
Show file tree
Hide file tree
Showing 32 changed files with 1,255 additions and 712 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ NEXT_PUBLIC_LICENSE_CONSENT=''
DATABASE_URL="postgresql://postgres:@localhost:5432/calendso?schema=public"

GOOGLE_API_CREDENTIALS='secret'
GOOGLE_REDIRECT_URL='https://localhost:3000/integrations/googlecalendar/callback'

BASE_URL='http://localhost:3000'
NEXT_PUBLIC_APP_URL='http://localhost:3000'

Expand Down
16 changes: 11 additions & 5 deletions components/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as DialogPrimitive from "@radix-ui/react-dialog";
import React from "react";
import React, { ReactNode } from "react";

type DialogProps = React.ComponentProps<typeof DialogPrimitive["Root"]>;
export type DialogProps = React.ComponentProps<typeof DialogPrimitive["Root"]>;
export function Dialog(props: DialogProps) {
const { children, ...other } = props;
return (
Expand Down Expand Up @@ -35,9 +35,15 @@ export function DialogHeader({ title, subtitle }: DialogHeaderProps) {
<h3 className="font-cal text-gray-900 text-lg font-bold leading-6" id="modal-title">
{title}
</h3>
<div>
<p className="text-gray-400 text-sm">{subtitle}</p>
</div>
<div className="text-gray-400 text-sm">{subtitle}</div>
</div>
);
}

export function DialogFooter(props: { children: ReactNode }) {
return (
<div>
<div className="mt-5 flex space-x-2 justify-end">{props.children}</div>
</div>
);
}
Expand Down
72 changes: 72 additions & 0 deletions components/List.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Link from "next/link";
import { createElement } from "react";

import classNames from "@lib/classNames";

export function List(props: JSX.IntrinsicElements["ul"]) {
return (
<ul {...props} className={classNames("overflow-hidden rounded-sm sm:mx-0", props.className)}>
{props.children}
</ul>
);
}

export type ListItemProps = { expanded?: boolean } & ({ href?: never } & JSX.IntrinsicElements["li"]);

export function ListItem(props: ListItemProps) {
const { href, expanded, ...passThroughProps } = props;

const elementType = href ? "a" : "li";

const element = createElement(
elementType,
{
...passThroughProps,
className: classNames(
"items-center bg-white min-w-0 flex-1 flex border-gray-200",
expanded ? "my-2 border" : "border -mb-px last:mb-0",
props.className,
(props.onClick || href) && "hover:bg-neutral-50"
),
},
props.children
);

return href ? (
<Link passHref href={href}>
{element}
</Link>
) : (
element
);
}

export function ListItemTitle<TComponent extends keyof JSX.IntrinsicElements = "span">(
props: JSX.IntrinsicElements[TComponent] & { component?: TComponent }
) {
const { component = "span", ...passThroughProps } = props;

return createElement(
component,
{
...passThroughProps,
className: classNames("text-sm font-medium text-neutral-900 truncate", props.className),
},
props.children
);
}

export function ListItemText<TComponent extends keyof JSX.IntrinsicElements = "span">(
props: JSX.IntrinsicElements[TComponent] & { component?: TComponent }
) {
const { component = "span", ...passThroughProps } = props;

return createElement(
component,
{
...passThroughProps,
className: classNames("text-sm text-gray-500", props.className),
},
props.children
);
}
37 changes: 31 additions & 6 deletions components/Shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import LicenseBanner from "@ee/components/LicenseBanner";
import HelpMenuItemDynamic from "@ee/lib/intercom/HelpMenuItemDynamic";

import classNames from "@lib/classNames";
import { shouldShowOnboarding } from "@lib/getting-started";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
import { trpc } from "@lib/trpc";

Expand All @@ -29,10 +30,7 @@ import Logo from "./Logo";

function useMeQuery() {
const [session] = useSession();
const meQuery = trpc.useQuery(["viewer.me"], {
// refetch max once per 5s
staleTime: 5000,
});
const meQuery = trpc.useQuery(["viewer.me"]);

useEffect(() => {
// refetch if sesion changes
Expand All @@ -59,6 +57,26 @@ function useRedirectToLoginIfUnauthenticated() {
}, [loading, session, router]);
}

export function ShellSubHeading(props: {
title: ReactNode;
subtitle?: ReactNode;
actions?: ReactNode;
className?: string;
}) {
return (
<div className={classNames("block sm:flex justify-between mb-3", props.className)}>
<div>
{/* TODO should be Roboto */}
<h2 className="text-lg font-bold text-gray-900 flex items-center content-center space-x-2">
{props.title}
</h2>
{props.subtitle && <p className="text-sm text-neutral-500 mr-4">{props.subtitle}</p>}
</div>
{props.actions && <div className="mb-4 flex-shrink-0">{props.actions}</div>}
</div>
);
}

export default function Shell(props: {
centered?: boolean;
title?: string;
Expand All @@ -74,6 +92,15 @@ export default function Shell(props: {
const telemetry = useTelemetry();
const query = useMeQuery();

useEffect(
function redirectToOnboardingIfNeeded() {
if (query.data && shouldShowOnboarding(query.data)) {
router.push("/getting-started");
}
},
[query.data, router]
);

const navigation = [
{
name: "Event Types",
Expand Down Expand Up @@ -209,7 +236,6 @@ export default function Shell(props: {
<div className="mb-4 flex-shrink-0">{props.CTA}</div>
</div>
<div className="px-4 sm:px-6 md:px-8">{props.children}</div>

{/* show bottom navigation for md and smaller (tablet and phones) */}
<nav className="bottom-nav md:hidden flex fixed bottom-0 bg-white w-full shadow">
{/* note(PeerRich): using flatMap instead of map to remove settings from bottom nav */}
Expand Down Expand Up @@ -239,7 +265,6 @@ export default function Shell(props: {
)
)}
</nav>

{/* add padding to content for mobile navigation*/}
<div className="block md:hidden pt-12" />
</div>
Expand Down
63 changes: 63 additions & 0 deletions components/form/fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useId } from "@radix-ui/react-id";
import { forwardRef, ReactNode } from "react";
import { FormProvider, UseFormReturn } from "react-hook-form";

import classNames from "@lib/classNames";

export const Input = forwardRef<HTMLInputElement, JSX.IntrinsicElements["input"]>(function Input(props, ref) {
return (
<input
{...props}
ref={ref}
className={classNames(
"mt-1 block w-full border border-gray-300 rounded-sm shadow-sm py-2 px-3 focus:outline-none focus:ring-neutral-500 focus:border-neutral-500 sm:text-sm",
props.className
)}
/>
);
});

export function Label(props: JSX.IntrinsicElements["label"]) {
return (
<label {...props} className={classNames("block text-sm font-medium text-gray-700", props.className)}>
{props.children}
</label>
);
}

export const TextField = forwardRef<
HTMLInputElement,
{
label: ReactNode;
} & React.ComponentProps<typeof Input> & {
labelProps?: React.ComponentProps<typeof Label>;
}
>(function TextField(props, ref) {
const id = useId();
const { label, ...passThroughToInput } = props;

// TODO: use `useForm()` from RHF and get error state here too!
return (
<div>
<Label htmlFor={id} {...props.labelProps}>
{label}
</Label>
<Input id={id} {...passThroughToInput} ref={ref} />
</div>
);
});

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const Form = forwardRef<HTMLFormElement, { form: UseFormReturn<any> } & JSX.IntrinsicElements["form"]>(
function Form(props, ref) {
const { form, ...passThrough } = props;

return (
<FormProvider {...form}>
<form ref={ref} {...passThrough}>
{props.children}
</form>
</FormProvider>
);
}
);
Empty file.
2 changes: 2 additions & 0 deletions components/ui/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ReactNode } from "react";
export interface AlertProps {
title?: ReactNode;
message?: ReactNode;
actions?: ReactNode;
className?: string;
severity: "success" | "warning" | "error";
}
Expand Down Expand Up @@ -36,6 +37,7 @@ export function Alert(props: AlertProps) {
<h3 className="text-sm font-medium">{props.title}</h3>
<div className="text-sm">{props.message}</div>
</div>
{props.actions && <div className="text-sm">{props.actions}</div>}
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion components/ui/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const Badge = function Badge(props: BadgeProps) {
<span
{...passThroughProps}
className={classNames(
"font-bold px-2 py-0.5 inline-block rounded-sm",
"font-bold px-2 py-0.5 inline-block rounded-sm text-xs",
variant === "default" && "bg-yellow-100 text-yellow-800",
variant === "success" && "bg-green-100 text-green-800",
variant === "gray" && "bg-gray-200 text-gray-800",
Expand Down
12 changes: 7 additions & 5 deletions components/ui/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { forwardRef } from "react";
import classNames from "@lib/classNames";
import { SVGComponent } from "@lib/types/SVGComponent";

export type ButtonProps = {
export type ButtonBaseProps = {
color?: "primary" | "secondary" | "minimal" | "warn";
size?: "base" | "sm" | "lg" | "fab" | "icon";
loading?: boolean;
Expand All @@ -13,10 +13,12 @@ export type ButtonProps = {
StartIcon?: SVGComponent;
EndIcon?: SVGComponent;
shallow?: boolean;
} & (
| (Omit<JSX.IntrinsicElements["a"], "href"> & { href: LinkProps["href"] })
| (JSX.IntrinsicElements["button"] & { href?: never })
);
};
export type ButtonProps = ButtonBaseProps &
(
| (Omit<JSX.IntrinsicElements["a"], "href"> & { href: LinkProps["href"] })
| (JSX.IntrinsicElements["button"] & { href?: never })
);

export const Button = forwardRef<HTMLAnchorElement | HTMLButtonElement, ButtonProps>(function Button(
props: ButtonProps,
Expand Down
8 changes: 6 additions & 2 deletions components/ui/Switch.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useId } from "@radix-ui/react-id";
import * as Label from "@radix-ui/react-label";
import * as PrimitiveSwitch from "@radix-ui/react-switch";
import { useState } from "react";
Expand All @@ -16,7 +17,7 @@ export default function Switch(props) {
}
setChecked(change);
};

const id = useId();
return (
<div className="flex items-center h-[20px]">
<PrimitiveSwitch.Root
Expand All @@ -25,14 +26,17 @@ export default function Switch(props) {
onCheckedChange={onPrimitiveCheckedChange}
{...primitiveProps}>
<PrimitiveSwitch.Thumb
id={id}
className={classNames(
"bg-white w-[16px] h-[16px] block transition-transform",
checked ? "translate-x-[16px]" : "translate-x-0"
)}
/>
</PrimitiveSwitch.Root>
{label && (
<Label.Root className="text-neutral-700 text-sm align-text-top ml-3 font-medium cursor-pointer">
<Label.Root
htmlFor={id}
className="text-neutral-700 text-sm align-text-top ml-3 font-medium cursor-pointer">
{label}
</Label.Root>
)}
Expand Down
1 change: 1 addition & 0 deletions environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ declare namespace NodeJS {
readonly CALENDSO_ENCRYPTION_KEY: string | undefined;
readonly DATABASE_URL: string | undefined;
readonly GOOGLE_API_CREDENTIALS: string | undefined;
readonly GOOGLE_REDIRECT_URL: string | undefined;
readonly BASE_URL: string | undefined;
readonly NEXT_PUBLIC_BASE_URL: string | undefined;
readonly NEXT_PUBLIC_APP_URL: string | undefined;
Expand Down
Loading

0 comments on commit c3dc186

Please sign in to comment.