Skip to content

Commit

Permalink
Merge pull request #722 from mit-27/include-magic-link-into-webapp
Browse files Browse the repository at this point in the history
Integrate magic link into webapp via /magic-link Route
  • Loading branch information
rflihxyz authored Nov 19, 2024
2 parents 04bd803 + c18dc4f commit 230895f
Show file tree
Hide file tree
Showing 9 changed files with 1,024 additions and 119 deletions.
614 changes: 614 additions & 0 deletions apps/webapp/src/app/(Magic-Link)/magic-link/page.tsx

Large diffs are not rendered by default.

195 changes: 114 additions & 81 deletions apps/webapp/src/components/Connection/ConnectionTable.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
'use client'
"use client";

import { columns } from "./columns"
import { DataTable } from "../shared/data-table"
import { columns } from "./columns";
import { DataTable } from "../shared/data-table";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "../ui/dialog";
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
import { Button } from "../ui/button";
import { PlusCircledIcon } from "@radix-ui/react-icons";
import CopyLinkInput from "./CopyLinkInput";
Expand All @@ -19,49 +22,47 @@ import AddConnectionButton from "./AddConnectionButton";
import config from "@/lib/config";
import useMagicLinkStore from "@/state/magicLinkStore";
import useOrganisationStore from "@/state/organisationStore";
import { usePostHog } from 'posthog-js/react'
import { usePostHog } from "posthog-js/react";
import useProjectStore from "@/state/projectStore";

export default function ConnectionTable() {

const {idProject} = useProjectStore();
const { idProject } = useProjectStore();
const { data: connections, isLoading, error } = useConnections();
const [isGenerated, setIsGenerated] = useState(false);

const posthog = usePostHog()

const {uniqueLink} = useMagicLinkStore();
const {nameOrg} = useOrganisationStore();
const posthog = usePostHog();

if(isLoading){
return (
<DataTableLoading data={[]} columns={columns}/>
)
const { uniqueLink } = useMagicLinkStore();
const { nameOrg } = useOrganisationStore();

if (isLoading) {
return <DataTableLoading data={[]} columns={columns} />;
}

if (error) {
console.log("error connections..");
}

const linkedConnections = (filter: string) => connections?.filter((connection) => connection.status == filter);
}

const linkedConnections = (filter: string) =>
connections?.filter((connection) => connection.status == filter);
const ts = connections?.map((connection) => ({
organisation: nameOrg,
organisation: nameOrg,
app: connection.provider_slug,
vertical: connection.vertical,
category: connection.token_type,
vertical: connection.vertical,
category: connection.token_type,
status: connection.status,
linkedUser: connection.id_linked_user,
date: connection.created_at,
connectionToken: connection.connection_token!
}))
linkedUser: connection.id_linked_user,
date: connection.created_at,
connectionToken: connection.connection_token!,
}));

let link: string;
if(config.DISTRIBUTION == 'selfhost' && config.REDIRECT_WEBHOOK_INGRESS) {
link = `${config.MAGIC_LINK_DOMAIN}/?uniqueLink=${uniqueLink}&redirectIngressUri=${config.REDIRECT_WEBHOOK_INGRESS}`
}else{
link = `${config.MAGIC_LINK_DOMAIN}/?uniqueLink=${uniqueLink}`
if (config.DISTRIBUTION == "selfhost" && config.REDIRECT_WEBHOOK_INGRESS) {
link = `${config.WEBAPP_URL}/magic-link?uniqueLink=${uniqueLink}&redirectIngressUri=${config.REDIRECT_WEBHOOK_INGRESS}`;
} else {
link = `${config.WEBAPP_URL}/magic-link?uniqueLink=${uniqueLink}`;
}

return (
<>
<div className="hidden h-full flex-1 flex-col space-y-8 md:flex">
Expand All @@ -71,68 +72,100 @@ export default function ConnectionTable() {
<CardTitle className="text-lg font-medium">Linked</CardTitle>
</CardHeader>
<CardContent>
<p className="text-2xl font-bold">{linkedConnections("valid")?.length}</p>
<p className="text-2xl font-bold">
{linkedConnections("valid")?.length}
</p>
</CardContent>

</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-lg font-medium">Incomplete Link</CardTitle>
<CardTitle className="text-lg font-medium">
Incomplete Link
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-2xl font-bold">{linkedConnections("1")?.length}</p>
<p className="text-2xl font-bold">
{linkedConnections("1")?.length}
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-lg font-medium">Relink Needed</CardTitle>
<CardTitle className="text-lg font-medium">
Relink Needed
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-2xl font-bold">{linkedConnections("2")?.length}</p>
<p className="text-2xl font-bold">
{linkedConnections("2")?.length}
</p>
</CardContent>

</Card>


</div>
{isGenerated ? <Dialog open={isGenerated} onOpenChange={setIsGenerated}>
<DialogTrigger asChild>
<Button variant="outline" className="" onClick={() => {
posthog?.capture("add_new_connection_button_clicked", {
id_project: idProject,
mode: config.DISTRIBUTION
})}}
>
<PlusCircledIcon className="mr-2 h-4 w-4" />
Add New Connection
</Button>
</DialogTrigger>
<DialogContent className="sm:w-[450px]">
<DialogHeader>
<DialogTitle>Share this magic link with your customers</DialogTitle>
<DialogDescription>
Once they finish the oAuth flow, a new connection would be enabled.
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<CopyLinkInput />
</div>
</div>
<DialogFooter>
<Button variant="outline" size="sm" className="h-7 gap-1" type="submit" onClick={() => window.open(link, '_blank')}>
<p className="mr-2">Open Link</p>
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3 2C2.44772 2 2 2.44772 2 3V12C2 12.5523 2.44772 13 3 13H12C12.5523 13 13 12.5523 13 12V8.5C13 8.22386 12.7761 8 12.5 8C12.2239 8 12 8.22386 12 8.5V12H3V3L6.5 3C6.77614 3 7 2.77614 7 2.5C7 2.22386 6.77614 2 6.5 2H3ZM12.8536 2.14645C12.9015 2.19439 12.9377 2.24964 12.9621 2.30861C12.9861 2.36669 12.9996 2.4303 13 2.497L13 2.5V2.50049V5.5C13 5.77614 12.7761 6 12.5 6C12.2239 6 12 5.77614 12 5.5V3.70711L6.85355 8.85355C6.65829 9.04882 6.34171 9.04882 6.14645 8.85355C5.95118 8.65829 5.95118 8.34171 6.14645 8.14645L11.2929 3H9.5C9.22386 3 9 2.77614 9 2.5C9 2.22386 9.22386 2 9.5 2H12.4999H12.5C12.5678 2 12.6324 2.01349 12.6914 2.03794C12.7504 2.06234 12.8056 2.09851 12.8536 2.14645Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd"></path></svg>
{isGenerated ? (
<Dialog open={isGenerated} onOpenChange={setIsGenerated}>
<DialogTrigger asChild>
<Button
variant="outline"
className=""
onClick={() => {
posthog?.capture("add_new_connection_button_clicked", {
id_project: idProject,
mode: config.DISTRIBUTION,
});
}}
>
<PlusCircledIcon className="mr-2 h-4 w-4" />
Add New Connection
</Button>
</DialogFooter>
</DialogContent>
</Dialog> :
</DialogTrigger>
<DialogContent className="sm:w-[450px]">
<DialogHeader>
<DialogTitle>
Share this magic link with your customers
</DialogTitle>
<DialogDescription>
Once they finish the oAuth flow, a new connection would be
enabled.
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<CopyLinkInput />
</div>
</div>
<DialogFooter>
<Button
variant="outline"
size="sm"
className="h-7 gap-1"
type="submit"
onClick={() => window.open(link, "_blank")}
>
<p className="mr-2">Open Link</p>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M3 2C2.44772 2 2 2.44772 2 3V12C2 12.5523 2.44772 13 3 13H12C12.5523 13 13 12.5523 13 12V8.5C13 8.22386 12.7761 8 12.5 8C12.2239 8 12 8.22386 12 8.5V12H3V3L6.5 3C6.77614 3 7 2.77614 7 2.5C7 2.22386 6.77614 2 6.5 2H3ZM12.8536 2.14645C12.9015 2.19439 12.9377 2.24964 12.9621 2.30861C12.9861 2.36669 12.9996 2.4303 13 2.497L13 2.5V2.50049V5.5C13 5.77614 12.7761 6 12.5 6C12.2239 6 12 5.77614 12 5.5V3.70711L6.85355 8.85355C6.65829 9.04882 6.34171 9.04882 6.14645 8.85355C5.95118 8.65829 5.95118 8.34171 6.14645 8.14645L11.2929 3H9.5C9.22386 3 9 2.77614 9 2.5C9 2.22386 9.22386 2 9.5 2H12.4999H12.5C12.5678 2 12.6324 2.01349 12.6914 2.03794C12.7504 2.06234 12.8056 2.09851 12.8536 2.14645Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
) : (
<AddConnectionButton setIsGenerated={setIsGenerated} />
}
<Suspense>
{ts && <DataTable data={ts} columns={columns}/>}
</Suspense>
)}
<Suspense>{ts && <DataTable data={ts} columns={columns} />}</Suspense>
</div>
</>
)
}
);
}
92 changes: 54 additions & 38 deletions apps/webapp/src/components/Connection/CopyLinkInput.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
'use client'
"use client";

import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import useMagicLinkStore from '@/state/magicLinkStore';
import config from '@/lib/config';
import { useState } from 'react';
import { LoadingSpinner } from './LoadingSpinner';
import { toast } from 'sonner';
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import useMagicLinkStore from "@/state/magicLinkStore";
import config from "@/lib/config";
import { useState } from "react";
import { LoadingSpinner } from "./LoadingSpinner";
import { toast } from "sonner";

const CopyLinkInput = () => {
const [copied, setCopied] = useState(false);

const {uniqueLink} = useMagicLinkStore();
const { uniqueLink } = useMagicLinkStore();

let link: string;
if(config.DISTRIBUTION == 'selfhost' && config.REDIRECT_WEBHOOK_INGRESS) {
link = `${config.MAGIC_LINK_DOMAIN}/?uniqueLink=${uniqueLink}&redirectIngressUri=${config.REDIRECT_WEBHOOK_INGRESS}`
}else{
link = `${config.MAGIC_LINK_DOMAIN}/?uniqueLink=${uniqueLink}`
if (config.DISTRIBUTION == "selfhost" && config.REDIRECT_WEBHOOK_INGRESS) {
link = `${config.WEBAPP_URL}/magic-link?uniqueLink=${uniqueLink}&redirectIngressUri=${config.REDIRECT_WEBHOOK_INGRESS}`;
} else {
link = `${config.WEBAPP_URL}/magic-link?uniqueLink=${uniqueLink}`;
}

const handleCopy = async () => {
Expand All @@ -28,40 +28,56 @@ const CopyLinkInput = () => {
label: "Close",
onClick: () => console.log("Close"),
},
})
});
setCopied(true);
setTimeout(() => setCopied(false), 2000); // Reset copied state after 2 seconds
} catch (err) {
console.error('Failed to copy: ', err);
console.error("Failed to copy: ", err);
}
};

return (
<>
{uniqueLink !== 'https://' ?
<>
<Input
defaultValue={link}
readOnly
className="col-span-3 flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
/>
<Button
onClick={handleCopy}
variant="outline"
className=" text-white rounded-md" // Adjust the styling as needed
>
{copied ? 'Copied!' :
<>
<p className='mr-1'>Copy</p>
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.6788 2.95419C10.0435 2.53694 9.18829 2.54594 8.51194 3.00541C8.35757 3.11027 8.1921 3.27257 7.7651 3.69957L7.14638 4.31829C6.95112 4.51355 6.63454 4.51355 6.43928 4.31829C6.24401 4.12303 6.24401 3.80645 6.43928 3.61119L7.058 2.99247C7.0725 2.97797 7.08679 2.96366 7.1009 2.94955C7.47044 2.57991 7.70691 2.34336 7.95001 2.17822C8.94398 1.50299 10.2377 1.46813 11.2277 2.11832C11.4692 2.27689 11.7002 2.508 12.0515 2.85942C12.0662 2.8741 12.081 2.88898 12.0961 2.90408C12.1112 2.91917 12.1261 2.93405 12.1408 2.94871C12.4922 3.30001 12.7233 3.53102 12.8819 3.77248C13.5321 4.76252 13.4972 6.05623 12.822 7.0502C12.6568 7.2933 12.4203 7.52976 12.0507 7.89929C12.0366 7.9134 12.0222 7.92771 12.0077 7.94221L11.389 8.56093C11.1938 8.7562 10.8772 8.7562 10.6819 8.56093C10.4867 8.36567 10.4867 8.04909 10.6819 7.85383L11.3006 7.23511C11.7276 6.80811 11.8899 6.64264 11.9948 6.48827C12.4543 5.81192 12.4633 4.95675 12.046 4.32141C11.9513 4.17714 11.8009 4.02307 11.389 3.61119C10.9771 3.1993 10.8231 3.04893 10.6788 2.95419ZM4.31796 6.43961C4.51322 6.63487 4.51322 6.95146 4.31796 7.14672L3.69924 7.76544C3.27224 8.19244 3.10993 8.35791 3.00507 8.51227C2.54561 9.18863 2.53661 10.0438 2.95385 10.6791C3.0486 10.8234 3.19896 10.9775 3.61085 11.3894C4.02274 11.8012 4.17681 11.9516 4.32107 12.0464C4.95642 12.4636 5.81158 12.4546 6.48794 11.9951C6.6423 11.8903 6.80777 11.728 7.23477 11.301L7.85349 10.6823C8.04875 10.487 8.36533 10.487 8.5606 10.6823C8.75586 10.8775 8.75586 11.1941 8.5606 11.3894L7.94188 12.0081C7.92738 12.0226 7.91307 12.0369 7.89897 12.051C7.52943 12.4206 7.29296 12.6572 7.04986 12.8223C6.05589 13.4976 4.76219 13.5324 3.77214 12.8822C3.53068 12.7237 3.29967 12.4925 2.94837 12.1411C2.93371 12.1264 2.91883 12.1116 2.90374 12.0965C2.88865 12.0814 2.87377 12.0665 2.8591 12.0518C2.50766 11.7005 2.27656 11.4695 2.11799 11.2281C1.4678 10.238 1.50265 8.94432 2.17788 7.95035C2.34303 7.70724 2.57957 7.47077 2.94922 7.10124C2.96333 7.08713 2.97763 7.07283 2.99213 7.05833L3.61085 6.43961C3.80611 6.24435 4.12269 6.24435 4.31796 6.43961Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd"></path></svg>
</>
}
</Button>
</> :
<div className='flex flex-row items-center justify-center'>
<LoadingSpinner className='mr-2 h-4 w-4 animate-spin'/>
{uniqueLink !== "https://" ? (
<>
<Input
defaultValue={link}
readOnly
className="col-span-3 flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
/>
<Button
onClick={handleCopy}
variant="outline"
className=" text-white rounded-md" // Adjust the styling as needed
>
{copied ? (
"Copied!"
) : (
<>
<p className="mr-1">Copy</p>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.6788 2.95419C10.0435 2.53694 9.18829 2.54594 8.51194 3.00541C8.35757 3.11027 8.1921 3.27257 7.7651 3.69957L7.14638 4.31829C6.95112 4.51355 6.63454 4.51355 6.43928 4.31829C6.24401 4.12303 6.24401 3.80645 6.43928 3.61119L7.058 2.99247C7.0725 2.97797 7.08679 2.96366 7.1009 2.94955C7.47044 2.57991 7.70691 2.34336 7.95001 2.17822C8.94398 1.50299 10.2377 1.46813 11.2277 2.11832C11.4692 2.27689 11.7002 2.508 12.0515 2.85942C12.0662 2.8741 12.081 2.88898 12.0961 2.90408C12.1112 2.91917 12.1261 2.93405 12.1408 2.94871C12.4922 3.30001 12.7233 3.53102 12.8819 3.77248C13.5321 4.76252 13.4972 6.05623 12.822 7.0502C12.6568 7.2933 12.4203 7.52976 12.0507 7.89929C12.0366 7.9134 12.0222 7.92771 12.0077 7.94221L11.389 8.56093C11.1938 8.7562 10.8772 8.7562 10.6819 8.56093C10.4867 8.36567 10.4867 8.04909 10.6819 7.85383L11.3006 7.23511C11.7276 6.80811 11.8899 6.64264 11.9948 6.48827C12.4543 5.81192 12.4633 4.95675 12.046 4.32141C11.9513 4.17714 11.8009 4.02307 11.389 3.61119C10.9771 3.1993 10.8231 3.04893 10.6788 2.95419ZM4.31796 6.43961C4.51322 6.63487 4.51322 6.95146 4.31796 7.14672L3.69924 7.76544C3.27224 8.19244 3.10993 8.35791 3.00507 8.51227C2.54561 9.18863 2.53661 10.0438 2.95385 10.6791C3.0486 10.8234 3.19896 10.9775 3.61085 11.3894C4.02274 11.8012 4.17681 11.9516 4.32107 12.0464C4.95642 12.4636 5.81158 12.4546 6.48794 11.9951C6.6423 11.8903 6.80777 11.728 7.23477 11.301L7.85349 10.6823C8.04875 10.487 8.36533 10.487 8.5606 10.6823C8.75586 10.8775 8.75586 11.1941 8.5606 11.3894L7.94188 12.0081C7.92738 12.0226 7.91307 12.0369 7.89897 12.051C7.52943 12.4206 7.29296 12.6572 7.04986 12.8223C6.05589 13.4976 4.76219 13.5324 3.77214 12.8822C3.53068 12.7237 3.29967 12.4925 2.94837 12.1411C2.93371 12.1264 2.91883 12.1116 2.90374 12.0965C2.88865 12.0814 2.87377 12.0665 2.8591 12.0518C2.50766 11.7005 2.27656 11.4695 2.11799 11.2281C1.4678 10.238 1.50265 8.94432 2.17788 7.95035C2.34303 7.70724 2.57957 7.47077 2.94922 7.10124C2.96333 7.08713 2.97763 7.07283 2.99213 7.05833L3.61085 6.43961C3.80611 6.24435 4.12269 6.24435 4.31796 6.43961Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
</>
)}
</Button>
</>
) : (
<div className="flex flex-row items-center justify-center">
<LoadingSpinner className="mr-2 h-4 w-4 animate-spin" />
</div>
}
)}
</>
);
};
Expand Down
Loading

0 comments on commit 230895f

Please sign in to comment.