Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
'use client';

import { trpc } from '@op/api/client';
import { Button } from '@op/ui/Button';
import { Modal, ModalBody, ModalFooter, ModalHeader } from '@op/ui/Modal';
import { TextField } from '@op/ui/TextField';
import { toast } from '@op/ui/Toast';
import { useRouter } from 'next/navigation';
import { useState } from 'react';

import { useTranslations } from '@/lib/i18n';

export const GenerateProcessModal = ({
isOpen,
onOpenChange,
}: {
isOpen: boolean;
onOpenChange: (isOpen: boolean) => void;
}) => {
const t = useTranslations();
const router = useRouter();
const [description, setDescription] = useState('');

const generateProcess =
trpc.decision.generateProcessFromDescription.useMutation({
onSuccess: (data) => {
onOpenChange(false);
router.push(`/decisions/${data.slug}/edit`);
},
onError: (error) => {
toast.error({
message: t('Failed to generate template'),
title: error.message,
});
},
});

const handleGenerate = () => {
if (description.trim().length < 10) {
return;
}
generateProcess.mutate({ description: description.trim() });
};

return (
<Modal isOpen={isOpen} onOpenChange={onOpenChange} isDismissable>
<ModalHeader>{t('Describe your decision-making process')}</ModalHeader>
<ModalBody className="flex flex-col gap-4">
<p className="text-neutral-gray4">
{t(
"Tell us about your decision-making process and we'll create a template for you.",
)}
</p>
<TextField
useTextArea
aria-label={t('Process description')}
value={description}
onChange={setDescription}
textareaProps={{
className: 'min-h-32 resize-y',
placeholder: t(
'e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting',
),
}}
/>
</ModalBody>
<ModalFooter>
<Button
color="neutral"
onPress={() => onOpenChange(false)}
className="w-full sm:w-auto"
>
{t('Cancel')}
</Button>
<Button
onPress={handleGenerate}
isPending={generateProcess.isPending}
isDisabled={
generateProcess.isPending || description.trim().length < 10
}
className="w-full sm:w-auto"
>
{generateProcess.isPending
? t('Generating your template...')
: t('Generate template')}
</Button>
</ModalFooter>
</Modal>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import { Avatar } from '@op/ui/Avatar';
import { Header1, Header2 } from '@op/ui/Header';
import { Skeleton } from '@op/ui/Skeleton';
import { useRouter } from 'next/navigation';
import { Suspense } from 'react';
import { Suspense, useState } from 'react';
import { LuSparkles } from 'react-icons/lu';

import { useTranslations } from '@/lib/i18n';

import { GenerateProcessModal } from './GenerateProcessModal';

export const ProcessBuilderProcessSelector = () => {
const t = useTranslations();

Expand All @@ -34,6 +37,7 @@ const TemplateList = () => {
const t = useTranslations();
const [templatesData] = trpc.decision.listProcesses.useSuspenseQuery({});
const templates = templatesData?.processes;
const [isGenerateModalOpen, setIsGenerateModalOpen] = useState(false);

const createDecisionInstance =
trpc.decision.createInstanceFromTemplate.useMutation({
Expand All @@ -42,26 +46,46 @@ const TemplateList = () => {
},
});

if (!templates?.length) {
return (
<div className="grid aspect-square h-64 items-center rounded-lg border bg-white text-center">
<p>{t('No templates found')}</p>
</div>
);
}
return (
<>
<button
className="flex w-full cursor-pointer flex-col gap-2 rounded-lg border border-dashed border-neutral-300 bg-white p-6 text-left transition-shadow hover:border-neutral-400 hover:shadow-md sm:w-72 md:aspect-[4/3] md:w-[360px] md:p-12 md:text-center"
onClick={() => setIsGenerateModalOpen(true)}
>
<div className="flex gap-2 md:flex-col md:items-center md:gap-6">
<div className="bg-primary-green1/20 flex size-10 shrink-0 items-center justify-center rounded-full md:size-20">
<LuSparkles className="text-primary-green1 size-5 md:size-8" />
</div>
<Header2 className="font-serif text-xl leading-6 font-light">
{t('Describe your process')}
</Header2>
</div>
<p className="text-neutral-gray4">
{t(
"Tell us about your decision-making process and we'll create a template for you.",
)}
</p>
</button>

{templates?.map((template) => (
<ProcessBuilderProcessCard
key={template.id}
template={template}
onSelect={() => {
createDecisionInstance.mutate({
templateId: template.id,
name: `New ${template.name}`,
});
}}
/>
))}

return templates.map((template) => (
<ProcessBuilderProcessCard
key={template.id}
template={template}
onSelect={() => {
createDecisionInstance.mutate({
templateId: template.id,
name: `New ${template.name}`,
});
}}
/>
));
<GenerateProcessModal
isOpen={isGenerateModalOpen}
onOpenChange={setIsGenerateModalOpen}
/>
</>
);
};

export const ProcessBuilderProcessCard = ({
Expand Down
10 changes: 9 additions & 1 deletion apps/app/src/lib/i18n/dictionaries/bn.json
Original file line number Diff line number Diff line change
Expand Up @@ -690,5 +690,13 @@
"Complete all required phase fields": "Complete all required phase fields",
"Create a proposal template": "Create a proposal template",
"Fix errors in the proposal template": "Fix errors in the proposal template",
"Invite members": "Invite members"
"Invite members": "Invite members",
"Describe your process": "Describe your process",
"Tell us about your decision-making process and we'll create a template for you.": "Tell us about your decision-making process and we'll create a template for you.",
"Describe your decision-making process": "Describe your decision-making process",
"Generate template": "Generate template",
"Generating your template...": "Generating your template...",
"Failed to generate template": "Failed to generate template",
"Process description": "Process description",
"e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting": "e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting"
}
10 changes: 9 additions & 1 deletion apps/app/src/lib/i18n/dictionaries/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -683,5 +683,13 @@
"Complete all required phase fields": "Complete all required phase fields",
"Create a proposal template": "Create a proposal template",
"Fix errors in the proposal template": "Fix errors in the proposal template",
"Invite members": "Invite members"
"Invite members": "Invite members",
"Describe your process": "Describe your process",
"Tell us about your decision-making process and we'll create a template for you.": "Tell us about your decision-making process and we'll create a template for you.",
"Describe your decision-making process": "Describe your decision-making process",
"Generate template": "Generate template",
"Generating your template...": "Generating your template...",
"Failed to generate template": "Failed to generate template",
"Process description": "Process description",
"e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting": "e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting"
}
10 changes: 9 additions & 1 deletion apps/app/src/lib/i18n/dictionaries/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -682,5 +682,13 @@
"Complete all required phase fields": "Complete all required phase fields",
"Create a proposal template": "Create a proposal template",
"Fix errors in the proposal template": "Fix errors in the proposal template",
"Invite members": "Invite members"
"Invite members": "Invite members",
"Describe your process": "Describe your process",
"Tell us about your decision-making process and we'll create a template for you.": "Tell us about your decision-making process and we'll create a template for you.",
"Describe your decision-making process": "Describe your decision-making process",
"Generate template": "Generate template",
"Generating your template...": "Generating your template...",
"Failed to generate template": "Failed to generate template",
"Process description": "Process description",
"e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting": "e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting"
}
10 changes: 9 additions & 1 deletion apps/app/src/lib/i18n/dictionaries/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -682,5 +682,13 @@
"Complete all required phase fields": "Complete all required phase fields",
"Create a proposal template": "Create a proposal template",
"Fix errors in the proposal template": "Fix errors in the proposal template",
"Invite members": "Invite members"
"Invite members": "Invite members",
"Describe your process": "Describe your process",
"Tell us about your decision-making process and we'll create a template for you.": "Tell us about your decision-making process and we'll create a template for you.",
"Describe your decision-making process": "Describe your decision-making process",
"Generate template": "Generate template",
"Generating your template...": "Generating your template...",
"Failed to generate template": "Failed to generate template",
"Process description": "Process description",
"e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting": "e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting"
}
10 changes: 9 additions & 1 deletion apps/app/src/lib/i18n/dictionaries/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -678,5 +678,13 @@
"Complete all required phase fields": "Complete all required phase fields",
"Create a proposal template": "Create a proposal template",
"Fix errors in the proposal template": "Fix errors in the proposal template",
"Invite members": "Invite members"
"Invite members": "Invite members",
"Describe your process": "Describe your process",
"Tell us about your decision-making process and we'll create a template for you.": "Tell us about your decision-making process and we'll create a template for you.",
"Describe your decision-making process": "Describe your decision-making process",
"Generate template": "Generate template",
"Generating your template...": "Generating your template...",
"Failed to generate template": "Failed to generate template",
"Process description": "Process description",
"e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting": "e.g., A hiring process where candidates submit applications, a committee reviews them, then we do ranked-choice voting"
}
Loading