Compare commits

...

45 Commits

Author SHA1 Message Date
Ryukemeister bd5256bbaf Merge branch 'main' into connect-component 2023-11-23 12:45:19 +05:30
Ryukemeister c5101366bc add component that connects to cal.com 2023-11-23 12:44:11 +05:30
Ryukemeister e6a39ebefe update comments for flow of connect calendar atom 2023-11-23 12:43:37 +05:30
Ryukemeister 9bead8aa61 minor tweaks 2023-11-23 12:42:59 +05:30
Ryukemeister a41e150497 update exports for connect component 2023-11-21 02:51:51 +05:30
Ryukemeister c3583a5077 split connect btn into video and calendars 2023-11-21 02:51:00 +05:30
Ryukemeister 5739af369a resolve conflicts 2023-11-21 02:31:54 +05:30
Ryukemeister ce9647951a Merge branch 'main' into connect-component 2023-11-09 14:58:16 +05:30
Ryukemeister 102e413c18 add async await to event handlers 2023-11-09 14:56:08 +05:30
Ryukemeister f14ab961a0 update comments 2023-11-06 13:31:30 +05:30
Ryukemeister 57b9c408f4 refactor 2023-11-06 12:43:29 +05:30
Ryukemeister 983d6140d9 add useCallback for event handler 2023-11-06 12:39:30 +05:30
Ryukemeister 0992c6dc9c minor fixes 2023-11-05 16:54:33 +05:30
Ryukemeister 580e6aa329 Merge branch 'main' into connect-component 2023-10-30 22:59:22 +05:30
Ryukemeister 210173d5cc add loading spinner 2023-10-30 13:12:06 +05:30
Ryukemeister 7e452a2f72 Merge branch 'main' into connect-component 2023-10-30 12:27:58 +05:30
Ryukemeister 36f9e6671c replace handleClick with generic onClick for button component 2023-10-27 18:19:15 +05:30
Ryukemeister 7c2c94bf27 cleanup comments, replace && and rename function handler 2023-10-27 16:01:48 +05:30
Ryukemeister 5f840391ea fixed classnames and moved onSucess inside of handleSubmit 2023-10-13 15:12:32 +05:30
Ryukemeister c16d5499ec added typings, replace classNames with cn and separate event handlers into onSuccess, onFailure and handleClick 2023-10-13 13:00:12 +05:30
Ryukemeister cac1e6880d shift button prop types inside button component 2023-10-13 12:58:41 +05:30
Ryukemeister 342820e0bd add icon for button 2023-10-10 23:13:51 +05:30
Ryukemeister e48b054252 add types for icon prop 2023-10-10 23:12:55 +05:30
Ryukemeister eade205ed3 Merge branch 'main' into connect-component 2023-10-09 20:46:26 +05:30
Ryukemeister 2a8d87865a fix path 2023-10-09 17:54:02 +05:30
Ryukemeister 801a2e5fda fixes 2023-10-09 13:07:48 +05:30
Ryukemeister a8b9fcc85d replace button with shadcn button component 2023-10-09 12:58:41 +05:30
Ryukemeister 7dc81dc792 setting up shadcn 2023-10-09 12:57:35 +05:30
Ryukemeister f0febb066d update classnames 2023-10-06 13:05:40 +05:30
Ryukemeister 6b4e988718 update classnames 2023-10-05 13:39:31 +05:30
Ryukemeister 51fa70b54d fix classNames styling 2023-10-05 12:34:17 +05:30
Ryukemeister 7ea09f3c6f Merge branch 'main' into connect-component 2023-10-04 13:37:09 +05:30
Ryukemeister b4b05f0447 update comments 2023-10-04 12:47:38 +05:30
Ryukemeister ad99adde9d add default styles 2023-10-04 12:46:06 +05:30
Ryukemeister c232582889 add props for custom styles 2023-10-04 12:45:24 +05:30
Ryukemeister c3be4f0167 fix type error 2023-10-03 14:23:21 +05:30
Ryukemeister af741a1b9e add callback for error 2023-09-29 13:39:54 +05:30
Ryukemeister 89fb9d2946 update typings 2023-09-29 13:39:11 +05:30
Ryukemeister 130d30c514 fix imports 2023-09-29 12:36:35 +05:30
Ryukemeister c928ea4945 add connect button to atoms export 2023-09-29 12:28:14 +05:30
Ryukemeister 5e72a12d94 export connect button component 2023-09-29 12:27:29 +05:30
Ryukemeister 2ead68faa3 rename button file 2023-09-29 12:26:42 +05:30
Ryukemeister 3f793acd0e update connect btn view 2023-09-29 12:18:02 +05:30
Ryukemeister c492c389f3 Add types for connect button 2023-09-29 12:13:00 +05:30
Ryukemeister 1754b0a04a Init connect button component 2023-09-29 12:07:14 +05:30
14 changed files with 399 additions and 3 deletions

View File

@ -0,0 +1,16 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.cjs",
"css": "globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}

View File

@ -0,0 +1,79 @@
import { cn } from "@/lib/utils";
import { Loader2 } from "lucide-react";
import { useState, useCallback } from "react";
import * as React from "react";
import { Button } from "../src/components/ui/button";
import type { AtomsGlobalConfigProps } from "../types";
interface ConnectButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
buttonText?: string;
icon?: JSX.Element;
onSuccess?: () => void;
onError?: () => void;
}
export function ConnectButton({
buttonText,
onClick,
onSuccess,
onError,
className,
icon,
}: ConnectButtonProps & AtomsGlobalConfigProps) {
const [isProcessing, setIsProcessing] = useState<boolean>(false);
const [errMsg, setErrMsg] = useState<string>("");
const handleSubmit = useCallback(
async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.preventDefault();
setIsProcessing(true);
try {
if (onClick) {
await onClick(e);
}
// if user wants to handle onSuccess inside onClick then it makes no sense to have a separate handler
// otherwise only if the user explicitly passes an onSuccess handler this gets triggered
if (onSuccess) {
await onSuccess();
}
} catch (error) {
setIsProcessing(false);
if (onError) {
await onError();
}
setErrMsg(error?.message);
}
setIsProcessing(false);
},
[onClick, onSuccess, onError]
);
return (
<div>
{/* TODO: Button needs a fix width in order to not resize at loading time */}
<Button
className={cn(
"bg-default text-default dark:text-muted dark:bg-muted relative inline-flex h-9 items-center whitespace-nowrap rounded-md px-4 py-2.5 text-sm font-medium !shadow-none transition-colors disabled:cursor-not-allowed",
className
)}
type="button"
disabled={isProcessing}
onClick={handleSubmit}>
{isProcessing ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
) : (
<>
{!!icon && icon}
{buttonText || "Install App"}
</>
)}
</Button>
{!!errMsg && <span>{errMsg}</span>}
</div>
);
}

View File

@ -0,0 +1,24 @@
import { useApiKey } from "cal-provider";
import { ConnectButton } from "connect/ConnectButton";
// This atom will initiate the oAuth connection process to the users of the platform
// the user would be redirected to grant oAuth permission page after the user has clicked on Connect Atom
// they will have to login/signup and then will be redirected to the permission page where they can see required permissions for the oAuth clients and can choose to deny or accept
export function ConnectCal() {
const key = useApiKey();
if (key === "no_key") {
return <>You havent entered a key</>;
}
if (key === "invalid_key") {
return <>This is not a valid key, please enter a valid key</>;
}
return (
<>
<ConnectButton>Connect to Cal.com</ConnectButton>
</>
);
}

View File

@ -0,0 +1,30 @@
import { useApiKey } from "cal-provider";
import { ConnectButton } from "connect/ConnectButton";
type ConnectCalendarProps = {
calendar: "google" | "outlook";
};
// TODO: implement flow for connecting to different calendars
// ideally when you click the connect calendar button it redirects the user to an accounts.google page
// this page asks the user permission for us to access their account
// after the user grants us all permissions we need to redirect the user back to where they started
// hopefully to the page wherever the button is situated
export function ConnectCalendar({ calendar }: ConnectCalendarProps) {
const key = useApiKey();
if (key === "no_key") {
return <>You havent entered a key</>;
}
if (key === "invalid_key") {
return <>This is not a valid key, please enter a valid key</>;
}
return (
<>
<ConnectButton>Connect {calendar}</ConnectButton>
</>
);
}

View File

@ -0,0 +1,26 @@
import { useApiKey } from "cal-provider";
import { ConnectButton } from "connect/ConnectButton";
type ConnectVideoProps = {
app: "zoom" | "google" | "facetime" | "cal video";
};
// TODO: figure out event handler flow for video apps
export function ConnectVideo({ app }: ConnectVideoProps) {
const key = useApiKey();
if (key === "no_key") {
return <>You havent entered a key</>;
}
if (key === "invalid_key") {
return <>This is not a valid key, please enter a valid key</>;
}
return (
<>
<ConnectButton>Connect {app}</ConnectButton>
</>
);
}

View File

@ -0,0 +1,4 @@
export { ConnectCalendar } from "connect/connect-calendar";
export { ConnectVideo } from "connect/connect-video";
export { ConnectButton } from "./ConnectButton";
export * from "../types";

View File

@ -8,3 +8,76 @@
@tailwind utilities;
@import "../ui/styles/shared-globals.css";
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

View File

@ -1,2 +1,5 @@
export { Booker } from "./booker/Booker";
export { ConnectButton } from "./connect/ConnectButton";
export { CalProvider } from "./cal-provider/index";
export { ConnectCalendar } from "connect/connect-calendar";
export { ConnectVideo } from "connect/connect-video";

View File

@ -11,6 +11,7 @@
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^15.0.1",
"@types/node": "^20.8.3",
"@types/react": "18.0.26",
"@types/react-dom": "^18.0.9",
"@vitejs/plugin-react": "^2.2.0",
@ -18,5 +19,13 @@
"typescript": "^4.9.4",
"vite": "^4.1.2"
},
"main": "./index"
"main": "./index",
"dependencies": {
"@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"lucide-react": "^0.284.0",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7"
}
}

View File

@ -0,0 +1,46 @@
import { cn } from "@/lib/utils";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
}
);
Button.displayName = "Button";
export { Button, buttonVariants };

View File

@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

View File

@ -3,5 +3,78 @@ const base = require("@calcom/config/tailwind-preset");
/** @type {import('tailwindcss').Config} */
module.exports = {
...base,
content: ["./bookings/**/*.tsx"],
darkMode: ["class"],
content: [
"./pages/**/*.{ts,tsx}",
"./components/**/*.{ts,tsx}",
"./app/**/*.{ts,tsx}",
"./src/**/*.{ts,tsx}",
"./bookings/**/*.tsx",
],
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: 0 },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: 0 },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [require("tailwindcss-animate")],
};

View File

@ -3,7 +3,8 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["/*"]
"~/*": ["/*"],
"@/*": ["./src/*"]
},
"resolveJsonModule": true
},

View File

@ -1,7 +1,12 @@
import react from "@vitejs/plugin-react";
import path from "path";
import { resolve } from "path";
import { defineConfig } from "vite";
// setting up shadcn for vite: https://ui.shadcn.com/docs/installation/vite
export default defineConfig({
plugins: [react()],
build: {
lib: {
entry: [resolve(__dirname, "booker/export.ts")],
@ -23,6 +28,7 @@ export default defineConfig({
fs: resolve("../../node_modules/rollup-plugin-node-builtins"),
path: resolve("../../node_modules/rollup-plugin-node-builtins"),
os: resolve("../../node_modules/rollup-plugin-node-builtins"),
"@": path.resolve(__dirname, "./src"),
},
},
});