diff --git a/apps/web/app/(app)/environments/[environmentId]/components/AddProductModal.tsx b/apps/web/app/(app)/environments/[environmentId]/components/AddProductModal.tsx index b8d2b5719f..9960c0da73 100644 --- a/apps/web/app/(app)/environments/[environmentId]/components/AddProductModal.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/components/AddProductModal.tsx @@ -7,6 +7,7 @@ import { PlusCircleIcon } from "@heroicons/react/24/outline"; import { useRouter } from "next/navigation"; import { useState } from "react"; import { useForm } from "react-hook-form"; +import toast from "react-hot-toast"; interface AddProductModalProps { environmentId: string; @@ -20,11 +21,19 @@ export default function AddProductModal({ environmentId, open, setOpen }: AddPro const { register, handleSubmit } = useForm(); const submitProduct = async (data: { name: string }) => { - setLoading(true); - const newEnv = await createProductAction(environmentId, data.name); - router.push(`/environments/${newEnv.id}/`); - setOpen(false); - setLoading(false); + try { + setLoading(true); + const newEnv = await createProductAction(environmentId, data.name); + + toast.success("Product created successfully!"); + router.push(`/environments/${newEnv.id}/`); + setOpen(false); + } catch (error) { + console.error(error); + toast.error(`Error: Unable to save product information`); + } finally { + setLoading(false); + } }; return ( diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/product/EditProductName.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/product/EditProductName.tsx index 420f444286..ce2bc15c82 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/product/EditProductName.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/product/EditProductName.tsx @@ -35,7 +35,8 @@ const EditProductName: React.FC = ({ product, environmentI router.refresh(); } catch (err) { - toast.error(`Error: ${err.message}`); + console.error(err); + toast.error(`Error: Unable to save product information`); } }; diff --git a/apps/web/components/team/CreateTeamModal.tsx b/apps/web/components/team/CreateTeamModal.tsx index 3a9e6a940d..38dd063b1a 100644 --- a/apps/web/components/team/CreateTeamModal.tsx +++ b/apps/web/components/team/CreateTeamModal.tsx @@ -18,13 +18,19 @@ export default function CreateTeamModal({ open, setOpen }: CreateTeamModalProps) const { register, handleSubmit } = useForm(); const submitTeam = async (data) => { - setLoading(true); - const newTeam = await createTeamAction(data.name); + try { + setLoading(true); + const newTeam = await createTeamAction(data.name); - toast.success("Team created successfully!"); - router.push(`/teams/${newTeam.id}`); - setOpen(false); - setLoading(false); + toast.success("Team created successfully!"); + router.push(`/teams/${newTeam.id}`); + setOpen(false); + } catch (error) { + console.error(error); + toast.error(`Unable to create team`); + } finally { + setLoading(false); + } }; return ( diff --git a/packages/database/migrations/20231011070343_unique_product_name/migration.sql b/packages/database/migrations/20231011070343_unique_product_name/migration.sql new file mode 100644 index 0000000000..9c5af4c60b --- /dev/null +++ b/packages/database/migrations/20231011070343_unique_product_name/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - A unique constraint covering the columns `[teamId,name]` on the table `Product` will be added. If there are existing duplicate values, this will fail. + +*/ +-- CreateIndex +CREATE UNIQUE INDEX "Product_teamId_name_key" ON "Product"("teamId", "name"); diff --git a/packages/database/schema.prisma b/packages/database/schema.prisma index 7060bd79cf..86980e107a 100644 --- a/packages/database/schema.prisma +++ b/packages/database/schema.prisma @@ -373,6 +373,8 @@ model Product { placement WidgetPlacement @default(bottomRight) clickOutsideClose Boolean @default(true) darkOverlay Boolean @default(false) + + @@unique([teamId, name]) } enum Plan { diff --git a/packages/lib/product/service.ts b/packages/lib/product/service.ts index 2cc61e3786..cad9fa99c2 100644 --- a/packages/lib/product/service.ts +++ b/packages/lib/product/service.ts @@ -194,6 +194,7 @@ export const createProduct = async ( if (!productInput.name) { throw new ValidationError("Product Name is required"); } + const { environments, ...data } = productInput; let product = await prisma.product.create({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c23bac3166..712c12eb32 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -469,6 +469,7 @@ importers: eslint-config-turbo: specifier: latest version: 1.10.15(eslint@8.51.0) + eslint-plugin-react: specifier: 7.33.2 version: 7.33.2(eslint@8.51.0) @@ -11630,6 +11631,7 @@ packages: stackframe: 1.3.4 dev: false + /es-abstract@1.22.2: resolution: {integrity: sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==} engines: {node: '>= 0.4'} @@ -12158,6 +12160,7 @@ packages: semver: 6.3.1 string.prototype.matchall: 4.0.10 + /eslint-plugin-turbo@1.10.15(eslint@8.51.0): resolution: {integrity: sha512-Tv4QSKV/U56qGcTqS/UgOvb9HcKFmWOQcVh3HEaj7of94lfaENgfrtK48E2CckQf7amhKs1i+imhCsNCKjkQyA==} peerDependencies: