Update automations UX for more consistency (#856)

* Update the automations UI to be a more suitable color distribution based on new designs

* Use accented colors for the metadata, update dark mode colors

* Update form to use icons as well and render more pretty inline form labels
This commit is contained in:
sabaimran
2024-07-20 23:52:23 -07:00
committed by GitHub
parent bf815e4463
commit 9cf52bb7e4
3 changed files with 318 additions and 188 deletions

View File

@@ -4,6 +4,11 @@ div.automationsLayout {
gap: 1rem; gap: 1rem;
} }
div.automationCard {
display: grid;
grid-template-rows: auto 1fr auto;
}
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
div.automationsLayout { div.automationsLayout {
grid-template-columns: 1fr; grid-template-columns: 1fr;

View File

@@ -47,8 +47,8 @@ import styles from './automations.module.css';
import ShareLink from '../components/shareLink/shareLink'; import ShareLink from '../components/shareLink/shareLink';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover'; import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover';
import { Clock, DotsThreeVertical, Envelope, Info, MapPinSimple, Pencil, Play, Plus, Trash } from '@phosphor-icons/react'; import { CalendarCheck, CalendarDot, CalendarDots, Clock, ClockAfternoon, ClockCounterClockwise, DotsThreeVertical, Envelope, Info, Lightning, MapPinSimple, Pencil, Play, Plus, Trash } from '@phosphor-icons/react';
import { useAuthenticatedData } from '../common/auth'; import { useAuthenticatedData, UserProfile } from '../common/auth';
import LoginPrompt from '../components/loginPrompt/loginPrompt'; import LoginPrompt from '../components/loginPrompt/loginPrompt';
import { useToast } from '@/components/ui/use-toast'; import { useToast } from '@/components/ui/use-toast';
import { ToastAction } from '@/components/ui/toast'; import { ToastAction } from '@/components/ui/toast';
@@ -223,6 +223,7 @@ interface AutomationsCardProps {
setNewAutomationData?: (data: AutomationsData) => void; setNewAutomationData?: (data: AutomationsData) => void;
isLoggedIn: boolean; isLoggedIn: boolean;
setShowLoginPrompt: (showLoginPrompt: boolean) => void; setShowLoginPrompt: (showLoginPrompt: boolean) => void;
authenticatedData: UserProfile | null;
} }
@@ -235,6 +236,33 @@ function AutomationsCard(props: AutomationsCardProps) {
const automation = props.automation; const automation = props.automation;
const [timeRecurrence, setTimeRecurrence] = useState('');
const [intervalString, setIntervalString] = useState('');
useEffect(() => {
// The updated automation data, if present, takes priority over the original automation data
const automationData = updatedAutomationData || automation;
setTimeRecurrence(getTimeRecurrenceFromCron(automationData.crontime));
const frequency = getEveryBlahFromCron(automationData.crontime);
console.log('frequency', frequency);
if (frequency === 'Day') {
setIntervalString('Daily');
} else if (frequency === 'Week') {
const dayOfWeek = getDayOfWeekFromCron(automationData.crontime);
if (dayOfWeek === undefined) {
setIntervalString('Weekly');
} else {
setIntervalString(`${weekDays[dayOfWeek]}`);
}
} else if (frequency === 'Month') {
const dayOfMonth = getDayOfMonthFromCron(automationData.crontime);
setIntervalString(`Monthly on the ${dayOfMonth}`);
}
}, [updatedAutomationData, props.automation]);
useEffect(() => { useEffect(() => {
const toastTitle = `Automation: ${updatedAutomationData?.subject || automation.subject}`; const toastTitle = `Automation: ${updatedAutomationData?.subject || automation.subject}`;
if (toastMessage) { if (toastMessage) {
@@ -254,117 +282,128 @@ function AutomationsCard(props: AutomationsCardProps) {
} }
return ( return (
<div className='p-2 rounded-lg bg-secondary hover:shadow-md'> <Card className={`bg-secondary h-full shadow-sm rounded-lg bg-gradient-to-b from-background to-slate-50 dark:to-gray-950 border ${styles.automationCard}`}>
<Card className='bg-secondary h-full shadow-none border-l-4 border-t-0 border-r-0 border-b-0 border-l-green-400 dark:border-green-600 rounded-none'> <CardHeader>
<CardHeader> <CardTitle className='line-clamp-2 leading-normal flex justify-between'>
<CardTitle className='line-clamp-2 leading-normal flex justify-between'> {updatedAutomationData?.subject || automation.subject}
{updatedAutomationData?.subject || automation.subject} <Popover>
<Popover> <PopoverTrigger asChild>
<PopoverTrigger asChild> <Button className='bg-background' variant={'ghost'}><DotsThreeVertical className='h-4 w-4' /></Button>
<Button className='bg-background' variant={'ghost'}><DotsThreeVertical className='h-4 w-4' /></Button> </PopoverTrigger>
</PopoverTrigger> <PopoverContent className='w-auto grid gap-2 text-left bg-secondary'>
<PopoverContent className='w-auto grid gap-2 text-left'> <Button variant={'destructive'}
<Button variant={'destructive'} className='justify-start'
className='justify-start' onClick={() => {
onClick={() => { if (props.suggestedCard) {
if (props.suggestedCard) { setIsDeleted(true);
setIsDeleted(true); return;
return; }
} deleteAutomation(automation.id.toString(), setIsDeleted);
deleteAutomation(automation.id.toString(), setIsDeleted); }}>
}}> <Trash className='h-4 w-4 mr-2' />Delete
<Trash className='h-4 w-4 mr-2' />Delete </Button>
</Button> {
{ !props.suggestedCard && (
!props.suggestedCard && ( <Dialog
<Dialog open={isEditing}
open={isEditing} onOpenChange={(open) => {
onOpenChange={(open) => { setIsEditing(open);
setIsEditing(open); }}
}} >
> <DialogTrigger asChild>
<DialogTrigger asChild> <Button variant="outline" className="justify-start">
<Button variant="outline" className="justify-start"> <Pencil className='h-4 w-4 mr-2' />Edit
<Pencil className='h-4 w-4 mr-2' />Edit </Button>
</Button> </DialogTrigger>
</DialogTrigger> <DialogContent>
<DialogContent> <DialogTitle>Edit Automation</DialogTitle>
<DialogTitle>Edit Automation</DialogTitle> <EditCard
<EditCard authenticatedData={props.authenticatedData}
automation={automation} automation={automation}
setIsEditing={setIsEditing} setIsEditing={setIsEditing}
isLoggedIn={props.isLoggedIn} isLoggedIn={props.isLoggedIn}
setShowLoginPrompt={props.setShowLoginPrompt} setShowLoginPrompt={props.setShowLoginPrompt}
setUpdatedAutomationData={setUpdatedAutomationData} setUpdatedAutomationData={setUpdatedAutomationData}
locationData={props.locationData} /> locationData={props.locationData} />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
) )
} }
{ {
!props.suggestedCard && ( !props.suggestedCard && (
<Button variant={'outline'} <Button variant={'outline'}
className="justify-start" className="justify-start"
onClick={() => { onClick={() => {
sendAPreview(automation.id.toString(), setToastMessage); sendAPreview(automation.id.toString(), setToastMessage);
}}> }}>
<Play className='h-4 w-4 mr-2' />Run Now <Play className='h-4 w-4 mr-2' />Run Now
</Button>
)
}
</PopoverContent>
</Popover>
</CardTitle>
<CardDescription className='mt-2'>
{updatedAutomationData?.schedule || cronToHumanReadableString(automation.crontime)}
</CardDescription>
</CardHeader>
<CardContent>
{updatedAutomationData?.query_to_run || automation.query_to_run}
</CardContent>
<CardFooter className="flex justify-end gap-2">
{
props.suggestedCard && props.setNewAutomationData && (
<Dialog
open={isEditing}
onOpenChange={(open) => {
setIsEditing(open);
}}
>
<DialogTrigger asChild>
<Button variant="outline">
<Plus className='h-4 w-4 mr-2' />
Add
</Button> </Button>
</DialogTrigger> )
<DialogContent> }
<DialogTitle>Add Automation</DialogTitle> <ShareLink
<EditCard buttonTitle="Share"
createNew={true} includeIcon={true}
automation={automation} buttonClassName='justify-start px-4 py-2 h-10'
setIsEditing={setIsEditing} buttonVariant={'outline' as keyof typeof buttonVariants}
isLoggedIn={props.isLoggedIn} title="Share Automation"
setShowLoginPrompt={props.setShowLoginPrompt} description="Copy the link below and share it with your coworkers or friends."
setUpdatedAutomationData={props.setNewAutomationData} url={createShareLink(automation)}
locationData={props.locationData} /> onShare={() => {
</DialogContent> navigator.clipboard.writeText(createShareLink(automation));
</Dialog> }} />
) </PopoverContent>
} </Popover>
<ShareLink </CardTitle>
buttonTitle="Share" </CardHeader>
includeIcon={true} <CardContent className='text-secondary-foreground'>
buttonVariant={'outline' as keyof typeof buttonVariants} {updatedAutomationData?.query_to_run || automation.query_to_run}
title="Share Automation" </CardContent>
description="Copy the link below and share it with your coworkers or friends." <CardFooter className="flex flex-col items-start md:flex-row md:justify-between md:items-center gap-2">
url={createShareLink(automation)} <div className='flex gap-2'>
onShare={() => { <div className='flex items-center bg-blue-50 rounded-lg p-1.5 border-blue-200 border dark:bg-blue-800 dark:border-blue-500'>
navigator.clipboard.writeText(createShareLink(automation)); <CalendarCheck className='h-4 w-4 mr-2 text-blue-700 dark:text-blue-300' />
}} /> <div className='text-s text-blue-700 dark:text-blue-300'>
</CardFooter> {timeRecurrence}
</Card> </div>
</div> </div>
<div className='flex items-center bg-purple-50 rounded-lg p-1.5 border-purple-200 border dark:bg-purple-800 dark:border-purple-500'>
<ClockAfternoon className='h-4 w-4 mr-2 text-purple-700 dark:text-purple-300' />
<div className='text-s text-purple-700 dark:text-purple-300'>
{intervalString}
</div>
</div>
</div>
{
props.suggestedCard && props.setNewAutomationData && (
<Dialog
open={isEditing}
onOpenChange={(open) => {
setIsEditing(open);
}}
>
<DialogTrigger asChild>
<Button variant="outline">
<Plus className='h-4 w-4 mr-2' />
Add
</Button>
</DialogTrigger>
<DialogContent>
<DialogTitle>Add Automation</DialogTitle>
<EditCard
authenticatedData={props.authenticatedData}
createNew={true}
automation={automation}
setIsEditing={setIsEditing}
isLoggedIn={props.isLoggedIn}
setShowLoginPrompt={props.setShowLoginPrompt}
setUpdatedAutomationData={props.setNewAutomationData}
locationData={props.locationData} />
</DialogContent>
</Dialog>
)
}
</CardFooter>
</Card>
) )
} }
@@ -373,6 +412,7 @@ interface SharedAutomationCardProps {
setNewAutomationData: (data: AutomationsData) => void; setNewAutomationData: (data: AutomationsData) => void;
isLoggedIn: boolean; isLoggedIn: boolean;
setShowLoginPrompt: (showLoginPrompt: boolean) => void; setShowLoginPrompt: (showLoginPrompt: boolean) => void;
authenticatedData: UserProfile | null;
} }
function SharedAutomationCard(props: SharedAutomationCardProps) { function SharedAutomationCard(props: SharedAutomationCardProps) {
@@ -407,8 +447,12 @@ function SharedAutomationCard(props: SharedAutomationCardProps) {
<DialogTrigger> <DialogTrigger>
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent>
<DialogTitle>Create Automation</DialogTitle> <DialogTitle>
<Plus className='h-4 w-4 mr-2' />
Create Automation
</DialogTitle>
<EditCard <EditCard
authenticatedData={props.authenticatedData}
createNew={true} createNew={true}
setIsEditing={setIsCreating} setIsEditing={setIsCreating}
setUpdatedAutomationData={props.setNewAutomationData} setUpdatedAutomationData={props.setNewAutomationData}
@@ -438,6 +482,7 @@ interface EditCardProps {
createNew?: boolean; createNew?: boolean;
isLoggedIn: boolean; isLoggedIn: boolean;
setShowLoginPrompt: (showLoginPrompt: boolean) => void; setShowLoginPrompt: (showLoginPrompt: boolean) => void;
authenticatedData: UserProfile | null;
} }
function EditCard(props: EditCardProps) { function EditCard(props: EditCardProps) {
@@ -524,7 +569,14 @@ function EditCard(props: EditCardProps) {
} }
return ( return (
<AutomationModificationForm form={form} onSubmit={onSubmit} create={props.createNew} isLoggedIn={props.isLoggedIn} setShowLoginPrompt={props.setShowLoginPrompt} /> <AutomationModificationForm
authenticatedData={props.authenticatedData}
locationData={props.locationData || null}
form={form}
onSubmit={onSubmit}
create={props.createNew}
isLoggedIn={props.isLoggedIn}
setShowLoginPrompt={props.setShowLoginPrompt} />
) )
} }
@@ -535,6 +587,8 @@ interface AutomationModificationFormProps {
create?: boolean; create?: boolean;
isLoggedIn: boolean; isLoggedIn: boolean;
setShowLoginPrompt: (showLoginPrompt: boolean) => void; setShowLoginPrompt: (showLoginPrompt: boolean) => void;
authenticatedData: UserProfile | null;
locationData: LocationData | null;
} }
function AutomationModificationForm(props: AutomationModificationFormProps) { function AutomationModificationForm(props: AutomationModificationFormProps) {
@@ -547,7 +601,7 @@ function AutomationModificationForm(props: AutomationModificationFormProps) {
function recommendationPill(recommendationText: string, onChange: (value: any, event: React.MouseEvent<HTMLButtonElement>) => void) { function recommendationPill(recommendationText: string, onChange: (value: any, event: React.MouseEvent<HTMLButtonElement>) => void) {
return ( return (
<Button <Button
className='text-xs bg-slate-50 h-auto p-1.5 m-1 rounded-full' className='text-xs bg-slate-50 dark:bg-slate-950 h-auto p-1.5 m-1 rounded-full'
variant="ghost" variant="ghost"
key={recommendationText} key={recommendationText}
onClick={(event) => { onClick={(event) => {
@@ -572,6 +626,16 @@ function AutomationModificationForm(props: AutomationModificationFormProps) {
props.onSubmit(values); props.onSubmit(values);
setIsSaving(true); setIsSaving(true);
})} className="space-y-8"> })} className="space-y-8">
<FormItem>
<FormLabel>Setup</FormLabel>
<FormDescription>
Emails will be sent to this address. Timezone and location data will be used to schedule automations.
{
props.locationData &&
metadataMap(props.locationData, props.authenticatedData)
}
</FormDescription>
</FormItem>
{ {
!props.create && ( !props.create && (
<FormField <FormField
@@ -600,14 +664,20 @@ function AutomationModificationForm(props: AutomationModificationFormProps) {
<FormItem <FormItem
className='w-full' className='w-full'
> >
<FormLabel>Frequency</FormLabel> <FormLabel>
Frequency
</FormLabel>
<FormDescription> <FormDescription>
How frequently should this automation run? How often should this automation run?
</FormDescription> </FormDescription>
<Select onValueChange={field.onChange} defaultValue={field.value}> <Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl> <FormControl>
<SelectTrigger className='w-[200px]'> <SelectTrigger className='w-[200px]'>
Every <SelectValue placeholder="" /> <div className='flex items-center'>
<CalendarDots className='h-4 w-4 mr-2 inline' />
Every
</div>
<SelectValue placeholder="" />
</SelectTrigger> </SelectTrigger>
</FormControl> </FormControl>
<SelectContent> <SelectContent>
@@ -631,11 +701,17 @@ function AutomationModificationForm(props: AutomationModificationFormProps) {
render={({ field }) => ( render={({ field }) => (
<FormItem <FormItem
className='w-full'> className='w-full'>
<FormLabel>Day of Week</FormLabel> <FormDescription>
Every week, on which day should this automation run?
</FormDescription>
<Select onValueChange={(value) => field.onChange(Number(value))} defaultValue={String(field.value)}> <Select onValueChange={(value) => field.onChange(Number(value))} defaultValue={String(field.value)}>
<FormControl> <FormControl>
<SelectTrigger className='w-[200px]'> <SelectTrigger className='w-[200px]'>
On <SelectValue placeholder="" /> <div className='flex items-center'>
<CalendarDot className='h-4 w-4 mr-2 inline' />
On
</div>
<SelectValue placeholder="" />
</SelectTrigger> </SelectTrigger>
</FormControl> </FormControl>
<SelectContent> <SelectContent>
@@ -663,11 +739,15 @@ function AutomationModificationForm(props: AutomationModificationFormProps) {
render={({ field }) => ( render={({ field }) => (
<FormItem <FormItem
className='w-full'> className='w-full'>
<FormLabel>Day of Month</FormLabel> <FormDescription>Every month, on which day should the automation run?</FormDescription>
<Select onValueChange={field.onChange} defaultValue={field.value}> <Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl> <FormControl>
<SelectTrigger className='w-[200px]'> <SelectTrigger className='w-[200px]'>
On the <SelectValue placeholder="" /> <div className='flex items-center'>
<CalendarDot className='h-4 w-4 mr-2 inline' />
On the
</div>
<SelectValue placeholder="" />
</SelectTrigger> </SelectTrigger>
</FormControl> </FormControl>
<SelectContent> <SelectContent>
@@ -705,7 +785,11 @@ function AutomationModificationForm(props: AutomationModificationFormProps) {
<Select onValueChange={field.onChange} defaultValue={field.value}> <Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl> <FormControl>
<SelectTrigger className='w-[200px]'> <SelectTrigger className='w-[200px]'>
At <SelectValue placeholder="" /> <div className='flex items-center'>
<ClockAfternoon className='h-4 w-4 mr-2 inline' />
At
</div>
<SelectValue placeholder="" />
</SelectTrigger> </SelectTrigger>
</FormControl> </FormControl>
<SelectContent> <SelectContent>
@@ -781,6 +865,30 @@ function AutomationModificationForm(props: AutomationModificationFormProps) {
) )
} }
function metadataMap(ipLocationData: LocationData, authenticatedData: UserProfile | null) {
return (
<div className='flex flex-wrap gap-2 items-center md:justify-start justify-end'>
{
authenticatedData ? (
<span className='rounded-lg text-sm border-secondary border p-1 flex items-center shadow-sm' ><Envelope className='h-4 w-4 mr-2 inline text-orange-500' shadow-s />{authenticatedData.email}</span>
)
: null
}
{
ipLocationData && (
<span className='rounded-lg text-sm border-secondary border p-1 flex items-center shadow-sm' ><MapPinSimple className='h-4 w-4 mr-2 inline text-purple-500' />{ipLocationData ? `${ipLocationData.city}, ${ipLocationData.country}` : 'Unknown'}</span>
)
}
{
ipLocationData && (
<span className='rounded-lg text-sm border-secondary border p-1 flex items-center shadow-sm' ><Clock className='h-4 w-4 mr-2 inline text-green-500' />{ipLocationData ? `${ipLocationData.timezone}` : 'Unknown'}</span>
)
}
</div>
)
}
export default function Automations() { export default function Automations() {
const authenticatedData = useAuthenticatedData(); const authenticatedData = useAuthenticatedData();
@@ -819,10 +927,31 @@ export default function Automations() {
return ( return (
<div> <div>
<h3 <div className='py-4 flex justify-between'>
className='text-xl py-4'> <h3
Automations className='text-xl font-bold'>
</h3> Automations
</h3>
<div className='flex flex-wrap gap-2 items-center md:justify-start justify-end'>
{
authenticatedData ? (
<span className='rounded-lg text-sm border-secondary border p-1 flex items-center shadow-sm' ><Envelope className='h-4 w-4 mr-2 inline text-orange-500' shadow-s />{authenticatedData.email}</span>
)
: null
}
{
ipLocationData && (
<span className='rounded-lg text-sm border-secondary border p-1 flex items-center shadow-sm' ><MapPinSimple className='h-4 w-4 mr-2 inline text-purple-500' />{ipLocationData ? `${ipLocationData.city}, ${ipLocationData.country}` : 'Unknown'}</span>
)
}
{
ipLocationData && (
<span className='rounded-lg text-sm border-secondary border p-1 flex items-center shadow-sm' ><Clock className='h-4 w-4 mr-2 inline text-green-500' />{ipLocationData ? `${ipLocationData.timezone}` : 'Unknown'}</span>
)
}
</div>
</div>
{ {
showLoginPrompt && ( showLoginPrompt && (
<LoginPrompt <LoginPrompt
@@ -830,75 +959,65 @@ export default function Automations() {
loginRedirectMessage={"Create an account to make your own automation"} /> loginRedirectMessage={"Create an account to make your own automation"} />
) )
} }
<Alert> <Alert className='bg-secondary border-none'>
<Info className="h-4 w-4" />
<AlertTitle>How this works!</AlertTitle>
<AlertDescription> <AlertDescription>
Automations help you structure your time by automating tasks you do regularly. Build your own, or try out our presets. Get results straight to your inbox. <Lightning weight={'fill'} className='h-4 w-4 text-purple-400 inline' />
<div className='mt-3' /> <span className='font-bold'>How it works</span> Automations help you structure your time by automating tasks you do regularly. Build your own, or try out our presets. Get results straight to your inbox.
{
authenticatedData ? (
<span className='rounded-full text-sm bg-blue-200 dark:bg-blue-600 p-2 m-1' ><Envelope className='h-4 w-4 mr-2 inline' />{authenticatedData.email}</span>
)
: (
<span> Sign in to create your own automations.</span>
)
}
{
ipLocationData && (
<span className='rounded-full text-sm bg-purple-200 dark:bg-purple-600 p-2 m-1' ><MapPinSimple className='h-4 w-4 mr-2 inline' />{ipLocationData ? `${ipLocationData.city}, ${ipLocationData.country}` : 'Unknown'}</span>
)
}
{
ipLocationData && (
<span className='rounded-full text-sm bg-green-200 dark:bg-green-600 p-2 m-1' ><Clock className='h-4 w-4 mr-2 inline' />{ipLocationData ? `${ipLocationData.timezone}` : 'Unknown'}</span>
)
}
</AlertDescription> </AlertDescription>
</Alert> </Alert>
<h3 <div className='flex justify-between py-4'>
className="text-xl py-4"> <h3
Your Creations className="text-xl">
</h3> Your Creations
</h3>
{
authenticatedData ? (
<Dialog
open={isCreating}
onOpenChange={(open) => {
setIsCreating(open);
}}
>
<DialogTrigger asChild>
<Button
className='shadow-sm'
variant="outline">
<Plus className='h-4 w-4 mr-2' />
Create Automation
</Button>
</DialogTrigger>
<DialogContent>
<DialogTitle>Create Automation</DialogTitle>
<EditCard
createNew={true}
setIsEditing={setIsCreating}
isLoggedIn={authenticatedData ? true : false}
authenticatedData={authenticatedData}
setShowLoginPrompt={setShowLoginPrompt}
setUpdatedAutomationData={setNewAutomationData}
locationData={ipLocationData} />
</DialogContent>
</Dialog>
)
: (
<Button
className='shadow-sm'
onClick={() => setShowLoginPrompt(true)}
variant={'outline'}>
<Plus className='h-4 w-4 mr-2' />
Create Automation
</Button>
)
}
</div>
<Suspense> <Suspense>
<SharedAutomationCard <SharedAutomationCard
authenticatedData={authenticatedData}
locationData={ipLocationData} locationData={ipLocationData}
isLoggedIn={authenticatedData ? true : false} isLoggedIn={authenticatedData ? true : false}
setShowLoginPrompt={setShowLoginPrompt} setShowLoginPrompt={setShowLoginPrompt}
setNewAutomationData={setNewAutomationData} /> setNewAutomationData={setNewAutomationData} />
</Suspense> </Suspense>
{
authenticatedData ? (
<Dialog
open={isCreating}
onOpenChange={(open) => {
setIsCreating(open);
}}
>
<DialogTrigger asChild className='fixed bottom-4 right-4'>
<Button variant="default">Create New</Button>
</DialogTrigger>
<DialogContent>
<DialogTitle>Create Automation</DialogTitle>
<EditCard
createNew={true}
setIsEditing={setIsCreating}
isLoggedIn={authenticatedData ? true : false}
setShowLoginPrompt={setShowLoginPrompt}
setUpdatedAutomationData={setNewAutomationData}
locationData={ipLocationData} />
</DialogContent>
</Dialog>
)
: (
<Button
onClick={() => setShowLoginPrompt(true)}
className='fixed bottom-4 right-4' variant={'default'}>
Create New
</Button>
)
}
{ {
((!personalAutomations || personalAutomations.length === 0) && (allNewAutomations.length == 0)) && ( ((!personalAutomations || personalAutomations.length === 0) && (allNewAutomations.length == 0)) && (
<div> <div>
@@ -918,6 +1037,7 @@ export default function Automations() {
<DialogContent> <DialogContent>
<DialogTitle>Create Automation</DialogTitle> <DialogTitle>Create Automation</DialogTitle>
<EditCard <EditCard
authenticatedData={authenticatedData}
createNew={true} createNew={true}
isLoggedIn={authenticatedData ? true : false} isLoggedIn={authenticatedData ? true : false}
setShowLoginPrompt={setShowLoginPrompt} setShowLoginPrompt={setShowLoginPrompt}
@@ -945,6 +1065,7 @@ export default function Automations() {
personalAutomations && personalAutomations.map((automation) => ( personalAutomations && personalAutomations.map((automation) => (
<AutomationsCard <AutomationsCard
key={automation.id} key={automation.id}
authenticatedData={authenticatedData}
automation={automation} automation={automation}
locationData={ipLocationData} locationData={ipLocationData}
isLoggedIn={authenticatedData ? true : false} isLoggedIn={authenticatedData ? true : false}
@@ -952,7 +1073,9 @@ export default function Automations() {
))} ))}
{ {
allNewAutomations.map((automation) => ( allNewAutomations.map((automation) => (
<AutomationsCard key={automation.id} <AutomationsCard
key={automation.id}
authenticatedData={authenticatedData}
automation={automation} automation={automation}
locationData={ipLocationData} locationData={ipLocationData}
isLoggedIn={authenticatedData ? true : false} isLoggedIn={authenticatedData ? true : false}
@@ -971,6 +1094,7 @@ export default function Automations() {
<AutomationsCard <AutomationsCard
setNewAutomationData={setNewAutomationData} setNewAutomationData={setNewAutomationData}
key={automation.id} key={automation.id}
authenticatedData={authenticatedData}
automation={automation} automation={automation}
locationData={ipLocationData} locationData={ipLocationData}
isLoggedIn={authenticatedData ? true : false} isLoggedIn={authenticatedData ? true : false}

View File

@@ -20,6 +20,7 @@ interface ShareLinkProps {
onShare: () => void; onShare: () => void;
buttonVariant?: keyof typeof buttonVariants; buttonVariant?: keyof typeof buttonVariants;
includeIcon?: boolean; includeIcon?: boolean;
buttonClassName?: string;
} }
function copyToClipboard(text: string) { function copyToClipboard(text: string) {
@@ -36,7 +37,7 @@ export default function ShareLink(props: ShareLinkProps) {
<DialogTrigger <DialogTrigger
asChild asChild
onClick={props.onShare}> onClick={props.onShare}>
<Button size="sm" className={`px-3`} variant={props.buttonVariant ?? 'default' as const}> <Button size="sm" className={`${props.buttonClassName || 'px-3'}`} variant={props.buttonVariant ?? 'default' as const}>
{ {
props.includeIcon && ( props.includeIcon && (
<Share className="w-4 h-4 mr-2" /> <Share className="w-4 h-4 mr-2" />