Compare commits

..

1 Commits

Author SHA1 Message Date
David Nguyen e7b18e820e chore: add code of conduct
Update contributing guidelines
2023-10-04 12:41:57 +11:00
48 changed files with 134 additions and 749 deletions
+6 -1
View File
@@ -9,5 +9,10 @@ npm install
# Copy the env file
cp .env.example .env
# Source the env file, export the variables
set -a
source .env
set +a
# Run the migrations
npm run prisma:migrate-dev
npm run -w @documenso/prisma prisma:migrate-dev
-50
View File
@@ -1,50 +0,0 @@
---
name: Bug Report
about: Create a bug report to help us improve
---
<!--- Please provide a general summary of the issue in the Title above -->
## Issue Description
<!--- Please provide a clear and concise description of the problem. -->
## Steps to Reproduce
<!--- Please provide step-by-step instructions to reproduce the issue. -->
<!--- Include code snippets, error messages, and any other relevant information. -->
1. Step 1
2. Step 2
3. ...
## Expected Behavior
<!--- Describe what you expected to happen. -->
## Current Behavior
<!--- Describe what is currently happening. -->
## Screenshots (optional)
<!--- If applicable, add screenshots to help explain the issue. -->
## Environment
<!--- Please provide information about your environment, such as operating system, browser, version, etc. -->
- OS: [e.g., Windows 10]
- Browser: [e.g., Chrome, Firefox]
- Version: [e.g., 2.0.1]
## Checklist
<!--- Please check the boxes that apply to this issue report. -->
<!--- You can add or remove items as needed. -->
- [ ] I have searched the existing issues to make sure this is not a duplicate.
- [ ] I have provided steps to reproduce the issue.
- [ ] I have included relevant environment information.
- [ ] I have included any relevant screenshots.
- [ ] I understand that this is a voluntary contribution and that there is no guarantee of resolution.
-41
View File
@@ -1,41 +0,0 @@
---
name: Feature Request
about: Suggest a new idea or enhancement for this project
---
<!--- Please provide a clear and concise title for your feature request -->
## Feature Description
<!--- Describe the feature you are requesting in detail. -->
<!--- Explain what problem it solves or what value it adds to the project. -->
## Use Case
<!--- Provide a scenario or use case where this feature would be beneficial. -->
<!--- Explain how users would interact with this feature and why it's important. -->
## Proposed Solution
<!--- If you have an idea of how this feature could be implemented, describe it here. -->
<!--- Include any technical details, UI/UX considerations, or design suggestions. -->
## Alternatives (optional)
<!--- Are there any alternative ways to achieve the same goal? -->
<!--- Describe other approaches that could be considered if this feature is not implemented. -->
## Additional Context
<!--- Add any additional context or information that might be relevant to the feature request. -->
## Checklist
<!--- Please check the boxes that apply to this feature request. -->
<!--- You can add or remove items as needed. -->
- [ ] I have searched the existing feature requests to make sure this is not a duplicate.
- [ ] I have provided a detailed description of the requested feature.
- [ ] I have explained the use case or scenario for this feature.
- [ ] I have included any relevant technical details or design suggestions.
- [ ] I understand that this is a suggestion and that there is no guarantee of implementation.
-41
View File
@@ -1,41 +0,0 @@
---
name: General Improvement
about: Suggest a minor enhancement or improvement for this project
---
<!--- Please provide a clear and concise title for your improvement suggestion -->
## Improvement Description
<!--- Describe the improvement you are suggesting in detail. -->
<!--- Explain what specific aspect of the project it addresses or enhances. -->
## Rationale
<!--- Explain why this improvement would be beneficial. -->
<!--- Share any context, pain points, or reasons for suggesting this change. -->
## Proposed Solution
<!--- If you have a suggestion for how this improvement could be implemented, describe it here. -->
<!--- Include any technical details, design suggestions, or other relevant information. -->
## Alternatives (optional)
<!--- Are there any alternative approaches to achieve the same improvement? -->
<!--- Describe other ways to address the issue or enhance the project. -->
## Additional Context
<!--- Add any additional context or information that might be relevant to the improvement suggestion. -->
## Checklist
<!--- Please check the boxes that apply to this improvement suggestion. -->
<!--- You can add or remove items as needed. -->
- [ ] I have searched the existing issues and improvement suggestions to avoid duplication.
- [ ] I have provided a clear description of the improvement being suggested.
- [ ] I have explained the rationale behind this improvement.
- [ ] I have included any relevant technical details or design suggestions.
- [ ] I understand that this is a suggestion and that there is no guarantee of implementation.
-49
View File
@@ -1,49 +0,0 @@
---
name: Pull Request
about: Submit changes to the project for review and inclusion
---
## Description
<!--- Describe the changes introduced by this pull request. -->
<!--- Explain what problem it solves or what feature/fix it adds. -->
## Related Issue
<!--- If this pull request is related to a specific issue, reference it here using #issue_number. -->
<!--- For example, "Fixes #123" or "Addresses #456". -->
## Changes Made
<!--- Provide a summary of the changes made in this pull request. -->
<!--- Include any relevant technical details or architecture changes. -->
- Change 1
- Change 2
- ...
## Testing Performed
<!--- Describe the testing that you have performed to validate these changes. -->
<!--- Include information about test cases, testing environments, and results. -->
- Tested feature X in scenario Y.
- Ran unit tests for component Z.
- Tested on browsers A, B, and C.
- ...
## Checklist
<!--- Please check the boxes that apply to this pull request. -->
<!--- You can add or remove items as needed. -->
- [ ] I have tested these changes locally and they work as expected.
- [ ] I have added/updated tests that prove the effectiveness of these changes.
- [ ] I have updated the documentation to reflect these changes, if applicable.
- [ ] I have followed the project's coding style guidelines.
- [ ] I have addressed the code review feedback from the previous submission, if applicable.
## Additional Notes
<!--- Provide any additional context or notes for the reviewers. -->
<!--- This might include details about design decisions, potential concerns, or anything else relevant. -->
@@ -1,40 +0,0 @@
---
name: Test Addition
about: Submit a new test, either unit or end-to-end (E2E), for review and inclusion
---
## Description
<!--- Provide a clear and concise description of the new test you are adding. -->
<!--- Explain the purpose of the test and what it aims to validate. -->
## Related Issue
<!--- If this test addition is related to a specific issue, reference it here using #issue_number. -->
<!--- For example, "Fixes #123" or "Addresses #456". -->
## Test Details
<!--- Describe the details of the test you're adding. -->
<!--- Include information about inputs, expected outputs, and any specific scenarios. -->
- Test Name: Name of the test
- Type: [Unit / E2E]
- Description: Brief description of what the test checks
- Inputs: What inputs the test uses (if applicable)
- Expected Output: What output or behavior the test expects
## Checklist
<!--- Please check the boxes that apply to this pull request. -->
<!--- You can add or remove items as needed. -->
- [ ] I have written the new test and ensured it works as intended.
- [ ] I have added necessary documentation to explain the purpose of the test.
- [ ] I have followed the project's testing guidelines and coding style.
- [ ] I have addressed any review feedback from previous submissions, if applicable.
## Additional Notes
<!--- Provide any additional context or notes for the reviewers. -->
<!--- This might include explanations about the testing approach or any potential concerns. -->
+3 -3
View File
@@ -9,7 +9,7 @@ updates:
labels:
- "ci dependencies"
- "ci"
open-pull-requests-limit: 0
open-pull-requests-limit: 2
- package-ecosystem: "npm"
directory: "/apps/marketing"
@@ -19,7 +19,7 @@ updates:
labels:
- "npm dependencies"
- "frontend"
open-pull-requests-limit: 0
open-pull-requests-limit: 2
- package-ecosystem: "npm"
directory: "/apps/web"
@@ -29,4 +29,4 @@ updates:
labels:
- "npm dependencies"
- "frontend"
open-pull-requests-limit: 0
open-pull-requests-limit: 2
-55
View File
@@ -1,55 +0,0 @@
tasks:
- init: |
npm i &&
npm run dx:up &&
cp .env.example .env &&
set -a; source .env &&
export NEXTAUTH_URL="$(gp url 3000)" &&
export NEXT_PUBLIC_WEBAPP_URL="$(gp url 3000)" &&
export NEXT_PUBLIC_MARKETING_URL="$(gp url 3001)"
command: npm run d
ports:
- port: 3000
visibility: public
onOpen: open-preview
- port: 3001
visibility: public
onOpen: open-preview
- port: 9000
visibility: public
onOpen: ignore
- port: 1100
visibility: private
onOpen: ignore
- port: 2500
visibility: private
onOpen: ignore
- port: 54320
visibility: private
onOpen: ignore
github:
prebuilds:
master: true
pullRequests: true
pullRequestsFromForks: true
addCheck: true
addComment: true
addBadge: true
vscode:
extensions:
- aaron-bond.better-comments
- bradlc.vscode-tailwindcss
- dbaeumer.vscode-eslint
- esbenp.prettier-vscode
- mikestead.dotenv
- unifiedjs.vscode-mdx
- GitHub.copilot-chat
- GitHub.copilot-labs
- GitHub.copilot
- GitHub.vscode-pull-request-github
- Prisma.prisma
- VisualStudioExptTeam.vscodeintellicode
+5 -5
View File
@@ -5,8 +5,8 @@ If you plan to contribute to Documenso, please take a moment to feel awesome ✨
## Before getting started
- Before jumping into a PR be sure to search [existing PRs](https://github.com/documenso/documenso/pulls) or [issues](https://github.com/documenso/documenso/issues) for an open or closed item that relates to your submission.
- Select an issue from [here](https://github.com/documenso/documenso/issues) or create a new one
- Consider the results from the discussion on the issue
- Select and issue from [here](https://github.com/documenso/documenso/issues) or create a new one
- Consider the results from the discussion in the issue
- Accept the [Contributor License Agreement](https://documen.so/cla) to ensure we can accept your contributions.
## Taking issues
@@ -27,14 +27,14 @@ Always feel free to ask questions or seek clarification on the issue.
## Developing
The development branch is <code>main</code>. All pull requests should be made against this branch. If you need help getting started, [join us on Discord](https://documen.so/discord).
The development branch is <code>main</code>. All pull request should be made against this branch. If you need help getting started, [join us on Discord](https://documen.so/discord).
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your
own GitHub account and then
[clone](https://help.github.com/articles/cloning-a-repository/) it to your local device.
2. Create a new branch:
- Create a new branch (include the issue id and something readable):
- Create a new branch (include the issue id and somthing readable):
```sh
git checkout -b doc-999-my-feature-or-fix
@@ -45,7 +45,7 @@ The development branch is <code>main</code>. All pull requests should be made ag
## Building
> **Note**
> Please ensure you can make a full production build before pushing code or creating PRs.
> Please be sure that you can make a full production build before pushing code or creating PRs.
You can build the project with:
+1 -17
View File
@@ -179,7 +179,7 @@ git clone https://github.com/documenso/documenso
- NEXT_PRIVATE_SMTP_FROM_NAME
- NEXT_PRIVATE_SMTP_FROM_ADDRESS
5. Create the database schema by running `npm run prisma:migrate-dev`
5. Create the database schema by running `npm run prisma:migrate-dev -w @documenso/prisma`
6. Run `npm run dev` root directory to start
@@ -254,22 +254,6 @@ containers:
- '::'
```
### I can't see environment variables in my package scripts
Wrap your package script with the `with:env` script like such:
```
npm run with:env -- npm run myscript
```
The same can be done when using `npx` for one of bin scripts:
```
npm run with:env -- npx myscript
```
This will load environment variables from your `.env` and `.env.local` files.
## Repo Activity
![Repository Activity](https://repobeats.axiom.co/api/embed/622a2e9aa709696f7226304b5b7178a5741b3868.svg)
+1 -1
View File
@@ -31,7 +31,7 @@
"react-confetti": "^6.1.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.9",
"react-icons": "^4.11.0",
"react-icons": "^4.8.0",
"recharts": "^2.7.2",
"sharp": "0.32.5",
"typescript": "5.1.6",
@@ -31,22 +31,6 @@ export const TEAM_MEMBERS = [
engagement: 'Full-Time',
joinDate: 'July 26th, 2023',
},
{
name: 'Catalin-Marinel Pit',
role: 'Software Engineer - II',
salary: 80_000,
location: 'Romania',
engagement: 'Full-Time',
joinDate: 'September 4th, 2023',
},
{
name: 'Gowdhama Rajan B',
role: 'Designer - III',
salary: 100_000,
location: 'India',
engagement: 'Full-Time',
joinDate: 'October 9th, 2023',
},
];
export const FUNDING_RAISED = [
+1 -4
View File
@@ -4,7 +4,6 @@ import { Caveat, Inter } from 'next/font/google';
import { FeatureFlagProvider } from '@documenso/lib/client-only/providers/feature-flag';
import { getAllAnonymousFlags } from '@documenso/lib/universal/get-feature-flag';
import { TrpcProvider } from '@documenso/trpc/react';
import { cn } from '@documenso/ui/lib/utils';
import { Toaster } from '@documenso/ui/primitives/toaster';
@@ -64,9 +63,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
<body>
<FeatureFlagProvider initialFlags={flags}>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<PlausibleProvider>
<TrpcProvider>{children}</TrpcProvider>
</PlausibleProvider>
<PlausibleProvider>{children}</PlausibleProvider>
</ThemeProvider>
</FeatureFlagProvider>
@@ -2,8 +2,8 @@
import Link from 'next/link';
import { Github } from 'lucide-react';
import { usePlausible } from 'next-plausible';
import { LuGithub } from 'react-icons/lu';
import { Button } from '@documenso/ui/primitives/button';
@@ -52,7 +52,7 @@ export const Callout = ({ starCount }: CalloutProps) => {
onClick={() => event('view-github')}
>
<Button variant="outline" className="rounded-full bg-transparent backdrop-blur-sm">
<LuGithub className="mr-2 h-5 w-5" />
<Github className="mr-2 h-5 w-5" />
Star on Github
{starCount && starCount > 0 && (
<span className="bg-primary dark:text-background -mr-2.5 ml-2.5 rounded-full px-2 py-1.5 text-xs">
@@ -1,6 +1,6 @@
'use client';
import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';
import { useSearchParams } from 'next/navigation';
@@ -55,8 +55,8 @@ export const ClaimPlanDialog = ({ className, planId, children }: ClaimPlanDialog
register,
handleSubmit,
formState: { errors, isSubmitting },
reset,
} = useForm<TClaimPlanDialogFormSchema>({
mode: 'onBlur',
defaultValues: {
name: params?.get('name') ?? '',
email: params?.get('email') ?? '',
@@ -91,12 +91,6 @@ export const ClaimPlanDialog = ({ className, planId, children }: ClaimPlanDialog
}
};
useEffect(() => {
if (!isSubmitting && !open) {
reset();
}
}, [open]);
return (
<Dialog open={open} onOpenChange={(value) => !isSubmitting && setOpen(value)}>
<DialogTrigger asChild>{children}</DialogTrigger>
@@ -5,20 +5,17 @@ import { HTMLAttributes } from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { Moon, Sun } from 'lucide-react';
import { Github, MessagesSquare, Moon, Sun, Twitter } from 'lucide-react';
import { useTheme } from 'next-themes';
import { FaXTwitter } from 'react-icons/fa6';
import { LiaDiscord } from 'react-icons/lia';
import { LuGithub } from 'react-icons/lu';
import { cn } from '@documenso/ui/lib/utils';
export type FooterProps = HTMLAttributes<HTMLDivElement>;
const SOCIAL_LINKS = [
{ href: 'https://twitter.com/documenso', icon: <FaXTwitter className="h-6 w-6" /> },
{ href: 'https://github.com/documenso/documenso', icon: <LuGithub className="h-6 w-6" /> },
{ href: 'https://documen.so/discord', icon: <LiaDiscord className="h-7 w-7" /> },
{ href: 'https://twitter.com/documenso', icon: <Twitter className="h-6 w-6" /> },
{ href: 'https://github.com/documenso/documenso', icon: <Github className="h-6 w-6" /> },
{ href: 'https://documen.so/discord', icon: <MessagesSquare className="h-6 w-6" /> },
];
const FOOTER_LINKS = [
@@ -4,8 +4,8 @@ import Image from 'next/image';
import Link from 'next/link';
import { Variants, motion } from 'framer-motion';
import { Github } from 'lucide-react';
import { usePlausible } from 'next-plausible';
import { LuGithub } from 'react-icons/lu';
import { match } from 'ts-pattern';
import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag';
@@ -122,7 +122,7 @@ export const Hero = ({ className, ...props }: HeroProps) => {
<Link href="https://github.com/documenso/documenso" onClick={() => event('view-github')}>
<Button variant="outline" className="rounded-full bg-transparent backdrop-blur-sm">
<LuGithub className="mr-2 h-5 w-5" />
<Github className="mr-2 h-5 w-5" />
Star on Github
</Button>
</Link>
@@ -4,9 +4,7 @@ import Image from 'next/image';
import Link from 'next/link';
import { motion, useReducedMotion } from 'framer-motion';
import { FaXTwitter } from 'react-icons/fa6';
import { LiaDiscord } from 'react-icons/lia';
import { LuGithub } from 'react-icons/lu';
import { Github, MessagesSquare, Twitter } from 'lucide-react';
import { Sheet, SheetContent } from '@documenso/ui/primitives/sheet';
@@ -113,7 +111,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
target="_blank"
className="text-foreground hover:text-foreground/80"
>
<FaXTwitter className="h-6 w-6" />
<Twitter className="h-6 w-6" />
</Link>
<Link
@@ -121,7 +119,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
target="_blank"
className="text-foreground hover:text-foreground/80"
>
<LuGithub className="h-6 w-6" />
<Github className="h-6 w-6" />
</Link>
<Link
@@ -129,7 +127,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
target="_blank"
className="text-foreground hover:text-foreground/80"
>
<LiaDiscord className="h-7 w-7" />
<MessagesSquare className="h-6 w-6" />
</Link>
</div>
</SheetContent>
@@ -1,8 +1,9 @@
'use client';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
export type PasswordRevealProps = {
password: string;
};
@@ -4,13 +4,14 @@ import { useEffect, useState } from 'react';
import Link from 'next/link';
import { Share } from 'lucide-react';
import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag';
import { base64 } from '@documenso/lib/universal/base64';
import { getFile } from '@documenso/lib/universal/upload/get-file';
import { DocumentWithRecipient } from '@documenso/prisma/types/document-with-recipient';
import DocumentDialog from '@documenso/ui/components/document/document-dialog';
import { DocumentDownloadButton } from '@documenso/ui/components/document/document-download-button';
import { DocumentShareButton } from '@documenso/ui/components/document/document-share-button';
import { SigningCard3D } from '@documenso/ui/components/signing-card';
import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button';
@@ -86,11 +87,11 @@ export const SinglePlayerModeSuccess = ({ className, document }: SinglePlayerMod
<div className="relative mt-8 w-full">
<div className={cn('flex flex-col items-center', className)}>
<div className="grid w-full max-w-sm grid-cols-2 gap-4">
<DocumentShareButton
documentId={document.id}
token={document.Recipient.token}
className="flex-1 bg-transparent backdrop-blur-sm"
/>
{/* TODO: Hook this up */}
<Button variant="outline" className="flex-1 bg-transparent backdrop-blur-sm" disabled>
<Share className="mr-2 h-5 w-5" />
Share
</Button>
<DocumentDownloadButton
className="flex-1 bg-transparent backdrop-blur-sm"
@@ -102,7 +103,7 @@ export const SinglePlayerModeSuccess = ({ className, document }: SinglePlayerMod
<Button
onClick={async () => onShowDocumentClick()}
loading={isFetchingDocumentFile}
className="z-10 col-span-2"
className="col-span-2"
>
Show document
</Button>
@@ -377,7 +377,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
</Card>
<Dialog open={showSigningDialog} onOpenChange={setShowSigningDialog}>
<DialogContent position="center">
<DialogContent>
<DialogHeader>
<DialogTitle>Add your signature</DialogTitle>
</DialogHeader>
@@ -391,7 +391,6 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
<SignaturePad
className="aspect-video w-full rounded-md border"
defaultValue={signatureDataUrl || ''}
onChange={setDraftSignatureDataUrl}
/>
@@ -1,8 +0,0 @@
import * as trpcNext from '@documenso/trpc/server/adapters/next';
import { createTrpcContext } from '@documenso/trpc/server/context';
import { appRouter } from '@documenso/trpc/server/router';
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext: async ({ req, res }) => createTrpcContext({ req, res }),
});
+1 -1
View File
@@ -36,7 +36,7 @@
"react-dom": "18.2.0",
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.43.9",
"react-icons": "^4.11.0",
"react-icons": "^4.8.0",
"react-rnd": "^10.4.1",
"sharp": "0.32.5",
"ts-pattern": "^5.0.5",
@@ -6,12 +6,13 @@ import { Edit, Pencil, Share } from 'lucide-react';
import { useSession } from 'next-auth/react';
import { match } from 'ts-pattern';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { Document, DocumentStatus, Recipient, SigningStatus, User } from '@documenso/prisma/client';
import { trpc } from '@documenso/trpc/react';
import { Button } from '@documenso/ui/primitives/button';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
export type DataTableActionButtonProps = {
row: Document & {
User: Pick<User, 'id' | 'name' | 'email'>;
@@ -46,7 +47,7 @@ export const DataTableActionButton = ({ row }: DataTableActionButtonProps) => {
documentId: row.id,
});
await copyToClipboard(`${process.env.NEXT_PUBLIC_WEBAPP_URL}/share/${slug}`).catch(() => null);
await copyToClipboard(`${window.location.origin}/share/${slug}`).catch(() => null);
toast({
title: 'Copied to clipboard',
@@ -1,7 +1,5 @@
'use client';
import { useState } from 'react';
import Link from 'next/link';
import {
@@ -18,7 +16,6 @@ import {
} from 'lucide-react';
import { useSession } from 'next-auth/react';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { getFile } from '@documenso/lib/universal/upload/get-file';
import { Document, DocumentStatus, Recipient, User } from '@documenso/prisma/client';
import { DocumentWithData } from '@documenso/prisma/types/document-with-data';
@@ -33,7 +30,7 @@ import {
} from '@documenso/ui/primitives/dropdown-menu';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { DeleteDraftDocumentDialog } from './delete-draft-document-dialog';
import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
export type DataTableActionDropdownProps = {
row: Document & {
@@ -47,8 +44,6 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) =
const { toast } = useToast();
const [, copyToClipboard] = useCopyToClipboard();
const [isDeleteDialogOpen, setDeleteDialogOpen] = useState(false);
if (!session) {
return null;
}
@@ -64,7 +59,6 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) =
// const isPending = row.status === DocumentStatus.PENDING;
const isComplete = row.status === DocumentStatus.COMPLETED;
// const isSigned = recipient?.signingStatus === SigningStatus.SIGNED;
const isDocumentDeletable = isOwner && row.status === DocumentStatus.DRAFT;
const onShareClick = async () => {
const { slug } = await createOrGetShareLink({
@@ -72,7 +66,7 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) =
documentId: row.id,
});
await copyToClipboard(`${process.env.NEXT_PUBLIC_WEBAPP_URL}/share/${slug}`).catch(() => null);
await copyToClipboard(`${window.location.origin}/share/${slug}`).catch(() => null);
toast({
title: 'Copied to clipboard',
@@ -153,7 +147,7 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) =
Void
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setDeleteDialogOpen(true)} disabled={!isDocumentDeletable}>
<DropdownMenuItem disabled>
<Trash2 className="mr-2 h-4 w-4" />
Delete
</DropdownMenuItem>
@@ -174,14 +168,6 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) =
Share
</DropdownMenuItem>
</DropdownMenuContent>
{isDocumentDeletable && (
<DeleteDraftDocumentDialog
id={row.id}
open={isDeleteDialogOpen}
onOpenChange={setDeleteDialogOpen}
/>
)}
</DropdownMenu>
);
};
@@ -1,89 +0,0 @@
import { useRouter } from 'next/navigation';
import { trpc as trpcReact } from '@documenso/trpc/react';
import { Button } from '@documenso/ui/primitives/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@documenso/ui/primitives/dialog';
import { useToast } from '@documenso/ui/primitives/use-toast';
type DeleteDraftDocumentDialogProps = {
id: number;
open: boolean;
onOpenChange: (_open: boolean) => void;
};
export const DeleteDraftDocumentDialog = ({
id,
open,
onOpenChange,
}: DeleteDraftDocumentDialogProps) => {
const router = useRouter();
const { toast } = useToast();
const { mutateAsync: deleteDocument, isLoading } =
trpcReact.document.deleteDraftDocument.useMutation({
onSuccess: () => {
router.refresh();
toast({
title: 'Document deleted',
description: 'Your document has been successfully deleted.',
duration: 5000,
});
onOpenChange(false);
},
});
const onDraftDelete = async () => {
try {
await deleteDocument({ id });
} catch {
toast({
title: 'Something went wrong',
description: 'This document could not be deleted at this time. Please try again.',
variant: 'destructive',
duration: 7500,
});
}
};
return (
<Dialog open={open} onOpenChange={(value) => !isLoading && onOpenChange(value)}>
<DialogContent>
<DialogHeader>
<DialogTitle>Do you want to delete this document?</DialogTitle>
<DialogDescription>
Please note that this action is irreversible. Once confirmed, your document will be
permanently deleted.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<div className="flex w-full flex-1 flex-nowrap gap-4">
<Button
type="button"
variant="secondary"
onClick={() => onOpenChange(false)}
className="flex-1"
>
Cancel
</Button>
<Button type="button" loading={isLoading} onClick={onDraftDelete} className="flex-1">
Delete
</Button>
</div>
</DialogFooter>
</DialogContent>
</Dialog>
);
};
@@ -66,7 +66,7 @@ export default async function DocumentsPage({ searchParams = {} }: DocumentsPage
<div className="mt-12 flex flex-wrap items-center justify-between gap-x-4 gap-y-8">
<h1 className="text-4xl font-semibold">Documents</h1>
<div className="-m-1 flex flex-wrap gap-x-4 gap-y-6 overflow-hidden p-1">
<div className="flex flex-wrap gap-x-4 gap-y-6 overflow-hidden">
<Tabs defaultValue={status} className="overflow-x-auto">
<TabsList>
{[
@@ -9,11 +9,12 @@ import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-f
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
import { DocumentStatus, FieldType } from '@documenso/prisma/client';
import { DocumentDownloadButton } from '@documenso/ui/components/document/document-download-button';
import { DocumentShareButton } from '@documenso/ui/components/document/document-share-button';
import { SigningCard3D } from '@documenso/ui/components/signing-card';
import signingCelebration from '~/assets/signing-celebration.png';
import { ShareButton } from './share-button';
export type CompletedSigningPageProps = {
params: {
token?: string;
@@ -88,7 +89,7 @@ export default async function CompletedSigningPage({
))}
<div className="mt-8 flex w-full max-w-sm items-center justify-center gap-4">
<DocumentShareButton documentId={document.id} token={recipient.token} />
<ShareButton documentId={document.id} token={recipient.token} />
<DocumentDownloadButton
className="flex-1"
@@ -2,13 +2,10 @@
import { HTMLAttributes, useState } from 'react';
import { Copy, Share } from 'lucide-react';
import { FaXTwitter } from 'react-icons/fa6';
import { Copy, Share, Twitter } from 'lucide-react';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { generateTwitterIntent } from '@documenso/lib/universal/generate-twitter-intent';
import { trpc } from '@documenso/trpc/react';
import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button';
import {
Dialog,
@@ -20,12 +17,14 @@ import {
} from '@documenso/ui/primitives/dialog';
import { useToast } from '@documenso/ui/primitives/use-toast';
export type DocumentShareButtonProps = HTMLAttributes<HTMLButtonElement> & {
import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
export type ShareButtonProps = HTMLAttributes<HTMLButtonElement> & {
token: string;
documentId: number;
};
export const DocumentShareButton = ({ token, documentId, className }: DocumentShareButtonProps) => {
export const ShareButton = ({ token, documentId }: ShareButtonProps) => {
const { toast } = useToast();
const [, copyToClipboard] = useCopyToClipboard();
@@ -60,7 +59,7 @@ export const DocumentShareButton = ({ token, documentId, className }: DocumentSh
slug = result.slug;
}
await copyToClipboard(`${process.env.NEXT_PUBLIC_WEBAPP_URL}/share/${slug}`).catch(() => null);
await copyToClipboard(`${window.location.origin}/share/${slug}`).catch(() => null);
toast({
title: 'Copied to clipboard',
@@ -85,7 +84,7 @@ export const DocumentShareButton = ({ token, documentId, className }: DocumentSh
window.open(
generateTwitterIntent(
`I just ${token ? 'signed' : 'sent'} a document with @documenso. Check it out!`,
`${process.env.NEXT_PUBLIC_WEBAPP_URL}/share/${slug}`,
`${window.location.origin}/share/${slug}`,
),
'_blank',
);
@@ -99,7 +98,7 @@ export const DocumentShareButton = ({ token, documentId, className }: DocumentSh
<Button
variant="outline"
disabled={!token || !documentId}
className={cn('flex-1', className)}
className="flex-1"
loading={isLoading}
>
{!isLoading && <Share className="mr-2 h-5 w-5" />}
@@ -120,17 +119,13 @@ export const DocumentShareButton = ({ token, documentId, className }: DocumentSh
<span className="font-medium text-blue-400">@documenso</span>
. Check it out!
<span className="mt-2 block" />
<span
className={cn('break-all font-medium text-blue-400', {
'animate-pulse': !shareLink?.slug,
})}
>
{process.env.NEXT_PUBLIC_WEBAPP_URL}/share/{shareLink?.slug || '...'}
<span className="break-all font-medium text-blue-400">
{window.location.origin}/share/{shareLink?.slug || '...'}
</span>
</div>
<Button variant="outline" className="mt-4" onClick={onTweetClick}>
<FaXTwitter className="mr-2 h-4 w-4" />
<Twitter className="mr-2 h-4 w-4" />
Tweet
</Button>
@@ -1,6 +1,6 @@
'use client';
import { useEffect, useMemo, useState, useTransition } from 'react';
import { useMemo, useState, useTransition } from 'react';
import { useRouter } from 'next/navigation';
@@ -48,7 +48,6 @@ export const SignatureField = ({ field, recipient }: SignatureFieldProps) => {
const [showSignatureModal, setShowSignatureModal] = useState(false);
const [localSignature, setLocalSignature] = useState<string | null>(null);
const [isLocalSignatureSet, setIsLocalSignatureSet] = useState(false);
const state = useMemo<SignatureFieldState>(() => {
if (!field.inserted) {
@@ -62,16 +61,9 @@ export const SignatureField = ({ field, recipient }: SignatureFieldProps) => {
return 'signed-text';
}, [field.inserted, signature?.signatureImageAsBase64]);
useEffect(() => {
if (!showSignatureModal && !isLocalSignatureSet) {
setLocalSignature(null);
}
}, [showSignatureModal, isLocalSignatureSet]);
const onSign = async (source: 'local' | 'provider' = 'provider') => {
try {
if (!providedSignature && !localSignature) {
setIsLocalSignatureSet(false);
setShowSignatureModal(true);
return;
}
@@ -186,7 +178,6 @@ export const SignatureField = ({ field, recipient }: SignatureFieldProps) => {
disabled={!localSignature}
onClick={() => {
setShowSignatureModal(false);
setIsLocalSignatureSet(true);
void onSign('local');
}}
>
@@ -4,6 +4,7 @@ import Link from 'next/link';
import {
CreditCard,
Github,
Key,
LogOut,
User as LucideUser,
@@ -15,7 +16,6 @@ import {
} from 'lucide-react';
import { signOut } from 'next-auth/react';
import { useTheme } from 'next-themes';
import { LuGithub } from 'react-icons/lu';
import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag';
import { isAdmin } from '@documenso/lib/next-auth/guards/is-admin';
@@ -130,7 +130,7 @@ export const ProfileDropdown = ({ user }: ProfileDropdownProps) => {
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<Link href="https://github.com/documenso/documenso" className="cursor-pointer">
<LuGithub className="mr-2 h-4 w-4" />
<Github className="mr-2 h-4 w-4" />
Star on Github
</Link>
</DropdownMenuItem>
+1 -38
View File
@@ -20,7 +20,6 @@ import { FormErrorMessage } from '../form/form-error-message';
export const ZPasswordFormSchema = z
.object({
currentPassword: z.string().min(6).max(72),
password: z.string().min(6).max(72),
repeatedPassword: z.string().min(6).max(72),
})
@@ -41,7 +40,6 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const [showCurrentPassword, setShowCurrentPassword] = useState(false);
const {
register,
@@ -50,7 +48,6 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
formState: { errors, isSubmitting },
} = useForm<TPasswordFormSchema>({
values: {
currentPassword: '',
password: '',
repeatedPassword: '',
},
@@ -59,10 +56,9 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
const { mutateAsync: updatePassword } = trpc.profile.updatePassword.useMutation();
const onFormSubmit = async ({ currentPassword, password }: TPasswordFormSchema) => {
const onFormSubmit = async ({ password }: TPasswordFormSchema) => {
try {
await updatePassword({
currentPassword,
password,
});
@@ -96,39 +92,6 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
className={cn('flex w-full flex-col gap-y-4', className)}
onSubmit={handleSubmit(onFormSubmit)}
>
<div>
<Label htmlFor="current-password" className="text-muted-foreground">
Current Password
</Label>
<div className="relative">
<Input
id="current-password"
type={showCurrentPassword ? 'text' : 'password'}
minLength={6}
maxLength={72}
autoComplete="current-password"
className="bg-background mt-2 pr-10"
{...register('currentPassword')}
/>
<Button
variant="link"
type="button"
className="absolute right-0 top-0 flex h-full items-center justify-center pr-3"
aria-label={showCurrentPassword ? 'Mask password' : 'Reveal password'}
onClick={() => setShowCurrentPassword((show) => !show)}
>
{showCurrentPassword ? (
<EyeOff className="text-muted-foreground h-5 w-5" />
) : (
<Eye className="text-muted-foreground h-5 w-5" />
)}
</Button>
</div>
<FormErrorMessage className="mt-1.5" error={errors.currentPassword} />
</div>
<div>
<Label htmlFor="password" className="text-muted-foreground">
Password
@@ -0,0 +1,28 @@
import { useState } from 'react';
export type CopiedValue = string | null;
export type CopyFn = (_text: string) => Promise<boolean>;
export function useCopyToClipboard(): [CopiedValue, CopyFn] {
const [copiedText, setCopiedText] = useState<CopiedValue>(null);
const copy: CopyFn = async (text) => {
if (!navigator?.clipboard) {
console.warn('Clipboard not supported');
return false;
}
// Try to save to clipboard then save it in the state if worked
try {
await navigator.clipboard.writeText(text);
setCopiedText(text);
return true;
} catch (error) {
console.warn('Copy failed', error);
setCopiedText(null);
return false;
}
};
return [copiedText, copy];
}
+14 -13
View File
@@ -15,8 +15,8 @@
"devDependencies": {
"@commitlint/cli": "^17.7.1",
"@commitlint/config-conventional": "^17.7.0",
"dotenv": "^16.3.1",
"dotenv-cli": "^7.3.0",
"dotenv": "^16.0.3",
"dotenv-cli": "^7.2.1",
"eslint": "^8.40.0",
"eslint-config-custom": "*",
"husky": "^8.0.0",
@@ -54,7 +54,7 @@
"react-confetti": "^6.1.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.9",
"react-icons": "^4.11.0",
"react-icons": "^4.8.0",
"recharts": "^2.7.2",
"sharp": "0.32.5",
"typescript": "5.1.6",
@@ -95,7 +95,7 @@
"react-dom": "18.2.0",
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.43.9",
"react-icons": "^4.11.0",
"react-icons": "^4.8.0",
"react-rnd": "^10.4.1",
"sharp": "0.32.5",
"ts-pattern": "^5.0.5",
@@ -9103,6 +9103,7 @@
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
"dev": true,
"engines": {
"node": ">=12"
},
@@ -9111,12 +9112,13 @@
}
},
"node_modules/dotenv-cli": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.3.0.tgz",
"integrity": "sha512-314CA4TyK34YEJ6ntBf80eUY+t1XaFLyem1k9P0sX1gn30qThZ5qZr/ZwE318gEnzyYP9yj9HJk6SqwE0upkfw==",
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.2.1.tgz",
"integrity": "sha512-ODHbGTskqRtXAzZapDPvgNuDVQApu4oKX8lZW7Y0+9hKA6le1ZJlyRS687oU9FXjOVEDU/VFV6zI125HzhM1UQ==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.3",
"dotenv": "^16.3.0",
"dotenv": "^16.0.0",
"dotenv-expand": "^10.0.0",
"minimist": "^1.2.6"
},
@@ -9128,6 +9130,7 @@
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz",
"integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==",
"dev": true,
"engines": {
"node": ">=12"
}
@@ -16356,9 +16359,9 @@
}
},
"node_modules/react-icons": {
"version": "4.11.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.11.0.tgz",
"integrity": "sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==",
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.10.1.tgz",
"integrity": "sha512-/ngzDP/77tlCfqthiiGNZeYFACw85fUjZtLbedmJ5DTlNDIwETxhwBzdOJ21zj4iJdvc0J3y7yOsX3PpxAJzrw==",
"peerDependencies": {
"react": "*"
}
@@ -19886,8 +19889,6 @@
"license": "MIT",
"dependencies": {
"@prisma/client": "5.3.1",
"dotenv": "^16.3.1",
"dotenv-cli": "^7.3.0",
"prisma": "5.3.1"
},
"devDependencies": {
+4 -8
View File
@@ -2,7 +2,6 @@
"private": true,
"scripts": {
"build": "turbo run build",
"build:web": "turbo run build --filter=@documenso/web",
"dev": "turbo run dev --filter=@documenso/web --filter=@documenso/marketing",
"start": "cd apps && cd web && next start",
"lint": "turbo run lint",
@@ -11,12 +10,9 @@
"commitlint": "commitlint --edit",
"clean": "turbo run clean && rimraf node_modules",
"d": "npm run dx && npm run dev",
"dx": "npm i && npm run dx:up && npm run prisma:migrate-dev",
"dx": "npm i && npm run dx:up && npm run prisma:migrate-dev -w @documenso/prisma",
"dx:up": "docker compose -f docker/compose-services.yml up -d",
"dx:down": "docker compose -f docker/compose-services.yml down",
"prisma:migrate-dev": "npm run with:env -- npm run prisma:migrate-dev -w @documenso/prisma",
"prisma:migrate-deploy": "npm run with:env -- npm run prisma:migrate-deploy -w @documenso/prisma",
"with:env": "dotenv -e .env -e .env.local --"
"dx:down": "docker compose -f docker/compose-services.yml down"
},
"engines": {
"npm": ">=8.6.0",
@@ -25,8 +21,8 @@
"devDependencies": {
"@commitlint/cli": "^17.7.1",
"@commitlint/config-conventional": "^17.7.0",
"dotenv": "^16.3.1",
"dotenv-cli": "^7.3.0",
"dotenv": "^16.0.3",
"dotenv-cli": "^7.2.1",
"eslint": "^8.40.0",
"eslint-config-custom": "*",
"husky": "^8.0.0",
@@ -1,13 +0,0 @@
'use server';
import { prisma } from '@documenso/prisma';
import { DocumentStatus } from '@documenso/prisma/client';
export type DeleteDraftDocumentOptions = {
id: number;
userId: number;
};
export const deleteDraftDocument = async ({ id, userId }: DeleteDraftDocumentOptions) => {
return await prisma.document.delete({ where: { id, userId, status: DocumentStatus.DRAFT } });
};
@@ -7,14 +7,9 @@ import { SALT_ROUNDS } from '../../constants/auth';
export type UpdatePasswordOptions = {
userId: number;
password: string;
currentPassword: string;
};
export const updatePassword = async ({
userId,
password,
currentPassword,
}: UpdatePasswordOptions) => {
export const updatePassword = async ({ userId, password }: UpdatePasswordOptions) => {
// Existence check
const user = await prisma.user.findFirstOrThrow({
where: {
@@ -22,29 +17,23 @@ export const updatePassword = async ({
},
});
if (!user.password) {
throw new Error('User has no password');
}
const hashedPassword = await hash(password, SALT_ROUNDS);
const isCurrentPasswordValid = await compare(currentPassword, user.password);
if (!isCurrentPasswordValid) {
throw new Error('Current password is incorrect.');
}
if (user.password) {
// Compare the new password with the old password
const isSamePassword = await compare(password, user.password);
// Compare the new password with the old password
const isSamePassword = await compare(password, user.password);
if (isSamePassword) {
throw new Error('Your new password cannot be the same as your old password.');
if (isSamePassword) {
throw new Error('Your new password cannot be the same as your old password.');
}
}
const hashedNewPassword = await hash(password, SALT_ROUNDS);
const updatedUser = await prisma.user.update({
where: {
id: userId,
},
data: {
password: hashedNewPassword,
password: hashedPassword,
},
});
-2
View File
@@ -18,8 +18,6 @@
},
"dependencies": {
"@prisma/client": "5.3.1",
"dotenv": "^16.3.1",
"dotenv-cli": "^7.3.0",
"prisma": "5.3.1"
},
"devDependencies": {
+3 -7
View File
@@ -12,16 +12,12 @@ export const authRouter = router({
return await createUser({ name, email, password, signature });
} catch (err) {
let message =
'We were unable to create your account. Please review the information you provided and try again.';
if (err instanceof Error && err.message === 'User already exists') {
message = 'User with this email already exists. Please use a different email address.';
}
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message,
message:
'We were unable to create your account. Please review the information you provided and try again.',
});
}
}),
@@ -1,7 +1,6 @@
import { TRPCError } from '@trpc/server';
import { createDocument } from '@documenso/lib/server-only/document/create-document';
import { deleteDraftDocument } from '@documenso/lib/server-only/document/delete-draft-document';
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
@@ -11,7 +10,6 @@ import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/s
import { authenticatedProcedure, procedure, router } from '../trpc';
import {
ZCreateDocumentMutationSchema,
ZDeleteDraftDocumentMutationSchema,
ZGetDocumentByIdQuerySchema,
ZGetDocumentByTokenQuerySchema,
ZSendDocumentMutationSchema,
@@ -78,25 +76,6 @@ export const documentRouter = router({
}
}),
deleteDraftDocument: authenticatedProcedure
.input(ZDeleteDraftDocumentMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { id } = input;
const userId = ctx.user.id;
return await deleteDraftDocument({ id, userId });
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to delete this document. Please try again later.',
});
}
}),
setRecipientsForDocument: authenticatedProcedure
.input(ZSetRecipientsForDocumentMutationSchema)
.mutation(async ({ input, ctx }) => {
@@ -61,9 +61,3 @@ export const ZSendDocumentMutationSchema = z.object({
});
export type TSendDocumentMutationSchema = z.infer<typeof ZSendDocumentMutationSchema>;
export const ZDeleteDraftDocumentMutationSchema = z.object({
id: z.number().min(1),
});
export type TDeleteDraftDocumentMutationSchema = z.infer<typeof ZDeleteDraftDocumentMutationSchema>;
@@ -40,12 +40,11 @@ export const profileRouter = router({
.input(ZUpdatePasswordMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { password, currentPassword } = input;
const { password } = input;
return await updatePassword({
userId: ctx.user.id,
password,
currentPassword,
});
} catch (err) {
let message =
@@ -6,7 +6,6 @@ export const ZUpdateProfileMutationSchema = z.object({
});
export const ZUpdatePasswordMutationSchema = z.object({
currentPassword: z.string().min(6),
password: z.string().min(6),
});
+1 -3
View File
@@ -6,9 +6,7 @@ import { shareLinkRouter } from './share-link-router/router';
import { procedure, router } from './trpc';
export const appRouter = router({
health: procedure.query(() => {
return { status: 'ok' };
}),
hello: procedure.query(() => 'Hello, world!'),
auth: authRouter,
profile: profileRouter,
document: documentRouter,
+2 -5
View File
@@ -16,13 +16,12 @@ const DialogPortal = ({
children,
position = 'start',
...props
}: DialogPrimitive.DialogPortalProps & { position?: 'start' | 'end' | 'center' }) => (
}: DialogPrimitive.DialogPortalProps & { position?: 'start' | 'end' }) => (
<DialogPrimitive.Portal className={cn(className)} {...props}>
<div
className={cn('fixed inset-0 z-50 flex justify-center sm:items-center', {
'items-start': position === 'start',
'items-end': position === 'end',
'items-center': position === 'center',
})}
>
{children}
@@ -50,9 +49,7 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
position?: 'start' | 'end' | 'center';
}
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & { position?: 'start' | 'end' }
>(({ className, children, position = 'start', ...props }, ref) => (
<DialogPortal position={position}>
<DialogOverlay />
@@ -97,7 +97,10 @@ export const DocumentFlowFormContainerStep = ({
return (
<div>
<p className="text-muted-foreground text-sm">
Step <span>{`${step} of ${maxStep}`}</span>
{title}{' '}
<span>
({step}/{maxStep})
</span>
</p>
<div className="bg-muted relative mt-4 h-[2px] rounded-md">
-103
View File
@@ -1,103 +0,0 @@
services:
- type: web
name: documenso-app
env: node
plan: free
buildCommand: npm i && npm run build:web
startCommand: npx prisma migrate deploy --schema packages/prisma/schema.prisma && npm run start
healthCheckPath: /api/trpc/health
envVars:
# Node Version
- key: NODE_VERSION
value: 18.17.0
- key: PORT
value: 10000
# Auth
- key: NEXTAUTH_URL
fromService:
name: documenso-app
type: web
envVarKey: RENDER_EXTERNAL_URL
- key: NEXTAUTH_SECRET
generateValue: true
# Database
- key: NEXT_PRIVATE_DATABASE_URL
fromDatabase:
name: documenso-db
property: connectionString
- key: NEXT_PRIVATE_DIRECT_DATABASE_URL
fromDatabase:
name: documenso-db
property: connectionString
# URLs
- key: NEXT_PUBLIC_WEBAPP_URL
fromService:
name: documenso-app
type: web
envVarKey: RENDER_EXTERNAL_URL
- key: NEXT_PUBLIC_MARKETING_URL
value: 'http://localhost:3001'
# SMTP
- key: NEXT_PRIVATE_SMTP_TRANSPORT
value: 'smtp-auth'
- key: NEXT_PRIVATE_SMTP_HOST
sync: false
- key: NEXT_PRIVATE_SMTP_PORT
sync: false
- key: NEXT_PRIVATE_SMTP_USERNAME
sync: false
- key: NEXT_PRIVATE_SMTP_PASSWORD
sync: false
- key: NEXT_PRIVATE_SMTP_FROM_NAME
sync: false
- key: NEXT_PRIVATE_SMTP_FROM_ADDRESS
sync: false
# Stripe
- key: NEXT_PRIVATE_STRIPE_API_KEY
sync: false
- key: NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET
sync: false
- key: NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID
sync: false
- key: NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID
sync: false
# Features
- key: NEXT_PUBLIC_POSTHOG_KEY
sync: false
- key: NEXT_PUBLIC_POSTHOG_HOST
value: 'https://eu.posthog.com'
- key: NEXT_PUBLIC_FEATURE_BILLING_ENABLED
sync: false
# Redis (Only required for marketing site, but added for completeness)
- key: NEXT_PRIVATE_REDIS_URL
sync: false
- key: NEXT_PRIVATE_REDIS_TOKEN
sync: false
# Storage
- key: NEXT_PUBLIC_UPLOAD_TRANSPORT
value: 'database'
- key: NEXT_PRIVATE_UPLOAD_ENDPOINT
sync: false
- key: NEXT_PRIVATE_UPLOAD_REGION
sync: false
- key: NEXT_PRIVATE_UPLOAD_BUCKET
sync: false
- key: NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID
sync: false
- key: NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY
sync: false
databases:
- name: documenso-db
plan: free