Compare commits

..

514 Commits

Author SHA1 Message Date
Mythie
af042a62cd fix: disable cancel button when there is no window history 2023-09-28 15:45:22 +10:00
Lucas Smith
df8bdda718 Merge pull request #450 from documenso/feat/resend-transport
feat: add resend mail transport
2023-09-28 14:07:18 +10:00
David Nguyen
873f99ae86 fix: resolve document title inconsistency (#452) 2023-09-28 13:56:22 +10:00
Lucas Smith
17fe135027 Merge pull request #451 from documenso/fix/445-signer-name-not-persisting
fix: do not overwrite new names or emails for signers
2023-09-28 13:07:26 +10:00
David Nguyen
2eed0ae063 feat: add posthog reverse proxy (#449) 2023-09-28 12:56:53 +10:00
Mythie
f4ae0389d8 fix: do not overwrite new names or emails for signers 2023-09-28 12:35:21 +10:00
Mythie
9bdff9a61f feat: add resend mail transport 2023-09-28 12:27:04 +10:00
Timur Ercan
cdb71c3a62 chore: greetings 2023-09-27 12:30:11 +02:00
Timur Ercan
39d7b3ca58 Merge branch 'feat/refresh' of https://github.com/documenso/documenso into feat/refresh 2023-09-27 12:19:14 +02:00
Timur Ercan
748c3636d5 chore: sync shop article and add missing and updated assets 2023-09-27 12:15:44 +02:00
Mythie
7bd847c0d3 chore: add missing migrations 2023-09-27 16:53:48 +10:00
Lucas Smith
a20b1e2f6a Merge pull request #350 from documenso/feat/redirect-signed-document
feat: redirect signed document to completed page
2023-09-27 15:09:07 +10:00
Mythie
572f9d5ad6 chore: styling updates 2023-09-27 14:58:10 +10:00
Mythie
e49c102e8c fix: lint errors 2023-09-27 09:11:56 +10:00
Mythie
2348221b03 fix: faster tooltips 2023-09-27 09:09:53 +10:00
Mythie
a0c327cfcf fix: share og updates 2023-09-27 09:03:53 +10:00
Mythie
ddbeb9e3db fix: twitter images 2023-09-27 08:02:51 +10:00
Mythie
e8205c1390 fix: better share links 2023-09-27 07:52:24 +10:00
Timur Ercan
fbb53fc8c3 chore: update mania shirt res 2023-09-26 22:06:41 +02:00
Timur Ercan
d7fed5a5dc feat: shop Article 2023-09-26 21:49:04 +02:00
Timur Ercan
3285881586 chore: typos 2023-09-26 11:39:30 +02:00
Timur Ercan
3ff61607a2 Merge pull request #370 from documenso/feat/mania
feat: malfunction mania blog post
2023-09-26 11:24:24 +02:00
Timur Ercan
2a124b03e9 Merge branch 'feat/refresh' into feat/mania 2023-09-26 11:24:13 +02:00
Timur Ercan
e1aa23bc55 chore: fix typo 2023-09-26 11:23:39 +02:00
Timur Ercan
818c5c7ba4 chore: fix lightmode logo 2023-09-26 11:19:32 +02:00
Timur Ercan
668011d1c7 Update README.md with M̸͍͚̽͒A̴̯͊͌L̴͖͖͘F̵̗̻́̅U̶̲̅͠N̸͙̰̓C̵̙̮̾T̸̜̙͌Í̷͎̯Ö̵̘̜́N̴̳͊̈ͅ ̶͔́M̸̡͐̾A̵̞̚N̴̤̏́Ǐ̸̩͂Ă̸͓͝ 2023-09-26 11:12:59 +02:00
Timur Ercan
562fd043a9 chore: typo 2023-09-26 10:31:41 +02:00
Timur Ercan
b4781c011c chore: alt text 2023-09-26 10:27:19 +02:00
Timur Ercan
5c7d3d5503 chore: update date 2023-09-26 10:26:16 +02:00
Timur Ercan
0f2b6c0ebf chore: remove unused image 2023-09-26 10:23:28 +02:00
Timur Ercan
ab5bdfeae4 chore: typo 2023-09-26 10:18:56 +02:00
Mythie
2d2615447e fix: redirectless authentication 2023-09-26 16:17:01 +10:00
Mythie
46465acd73 chore: quieten dependabot 2023-09-26 16:11:06 +10:00
Lucas Smith
2dea9ec3e7 Merge pull request #423 from documenso/feat/copy-or-tweet
feat: add dropdown to tweet or copy signing link
2023-09-26 16:08:43 +10:00
Mythie
584d5bd8ea fix: update share preview 2023-09-26 15:58:43 +10:00
Mythie
e4b6d42672 fix: styling updates 2023-09-26 15:56:11 +10:00
Timur Ercan
109ad190cf fix: text 2023-09-25 19:13:03 +02:00
Ephraim Atta-Duncan
78498793fa chore: refactor function 2023-09-25 11:21:39 +00:00
Ephraim Atta-Duncan
b2e916378d feat: add dropdown to tweet or copy signing link 2023-09-25 11:15:31 +00:00
Mythie
a52c19355a chore: sign document 2023-09-25 15:57:10 +10:00
Mythie
e67e96333b fix: dark mode for generic mdx content 2023-09-25 11:31:26 +10:00
Lucas Smith
7aa75b0c64 Merge pull request #403 from documenso/feat/single-player-mode
feat: single player mode
2023-09-25 11:25:58 +10:00
Mythie
9b1069f208 fix: remove usage of buffer 2023-09-25 11:24:55 +10:00
Mythie
abe20b8dcf fix: assorted updates 2023-09-25 11:17:59 +10:00
Mythie
58509c54a9 fix: feature flag client endpoint 2023-09-25 10:35:18 +10:00
Mythie
fd545cee0c chore: update env.example 2023-09-25 10:33:38 +10:00
Mythie
1f92bffe7d chore: remove console.log 2023-09-25 10:09:02 +10:00
Timur Ercan
5615627001 Merge pull request #419 from documenso/fix/incorporation
fix: company name
2023-09-24 21:53:10 +02:00
Timur Ercan
78c55875ef fix: company name 2023-09-24 21:52:09 +02:00
Mythie
a3674947b8 fix: single player dark mode and animation updates 2023-09-25 00:18:41 +10:00
Mythie
63cc57b035 fix: improve dark mode background patterns 2023-09-25 00:18:15 +10:00
Mythie
d4bc1eb0d1 fix: cors for feature flags 2023-09-25 00:16:01 +10:00
Mythie
c9f5496acb Merge remote-tracking branch 'origin/feat/refresh' into feat/single-player-mode 2023-09-24 22:18:01 +10:00
Mythie
99481b6144 feat: darker dark theme 2023-09-24 14:45:50 +10:00
Mythie
cee147bc9a fix: normalize recipients 2023-09-24 11:46:36 +10:00
Lucas Smith
3a825391b9 Merge pull request #399 from captain-Akshay/feat/handle_click
fix: cancel button handler
2023-09-23 22:19:57 +10:00
Lucas Smith
bb347e4614 Merge pull request #326 from documenso/feat/completed-share-link
feat: signing completed sharing link
2023-09-23 22:18:17 +10:00
Lucas Smith
68d624ac78 Merge branch 'feat/refresh' into feat/completed-share-link 2023-09-23 21:07:31 +10:00
David Nguyen
8012d665ae fix: firefox signing fields 2023-09-23 13:25:39 +10:00
Timur Ercan
fde53e355f chore: staging 2023-09-22 18:44:34 +02:00
Timur Ercan
8e0a10298e Merge branch 'feat/refresh' into feat/mania 2023-09-22 18:33:16 +02:00
Lucas Smith
1e5ecd79c2 Merge pull request #354 from documenso/feat/table-empty-state
feat: add empty document state
2023-09-22 23:36:42 +10:00
Lucas Smith
58f10268e2 Merge pull request #359 from documenso/feat/send-email
feat: send email when recipient is done signing and every recipient is done signing
2023-09-22 23:29:35 +10:00
Lucas Smith
43ce76d928 fix: remove unused import 2023-09-22 23:29:14 +10:00
Lucas Smith
201ba65e1c fix: remove unused import 2023-09-22 23:23:55 +10:00
Lucas Smith
0d130b17c8 fix: minor updates 2023-09-22 23:22:48 +10:00
Lucas Smith
2c90f767fd Merge branch 'feat/refresh' into feat/send-email 2023-09-22 23:19:43 +10:00
Lucas Smith
946b2fe129 fix: use named export 2023-09-22 23:15:30 +10:00
Lucas Smith
2a2dbb65c6 Merge branch 'feat/refresh' into feat/table-empty-state 2023-09-22 23:13:51 +10:00
Lucas Smith
ef2300a600 Merge pull request #343 from adithyaakrishna/feat/404
feat: added custom `not-found` or 404 pages
2023-09-22 23:11:34 +10:00
Lucas Smith
eea99ac871 Merge pull request #391 from documenso/feat/custom-emails
feat: send custom emails
2023-09-22 22:53:09 +10:00
Mythie
f4c7799537 fix: reverse meta relation and tidy code 2023-09-22 12:42:06 +00:00
David Nguyen
764c6b88c5 feat: update success page text 2023-09-22 16:35:49 +10:00
David Nguyen
989d7a351f feat: add uninserted field validation 2023-09-22 16:25:09 +10:00
Lucas Smith
78325d9b39 Merge branch 'feat/refresh' into feat/404 2023-09-22 15:01:49 +10:00
captain-Akshay
679fb80f9a fix: cancel button handler 2023-09-22 10:31:42 +05:30
David Nguyen
dc49277bf9 feat: add uninserted field validation 2023-09-22 12:27:39 +10:00
Lucas Smith
b3f26055d9 Merge pull request #395 from nsylke/nsylke-patch-10
fix: remove disallow property of _next from robots
2023-09-21 22:36:30 +10:00
Mythie
1b276a0469 fix: support optimise imports 2023-09-21 21:34:24 +10:00
Mythie
17fbf2673c Merge remote-tracking branch 'origin/feat/refresh' into feat/completed-share-link 2023-09-21 18:55:52 +10:00
Mythie
cdc50ec876 fix: resolve issues with open graph asset loading 2023-09-21 05:37:04 +00:00
nsylke
181af24b78 fix: remove disallow property of _next from robots 2023-09-20 20:46:23 -05:00
Mythie
4b13a42731 fix: tidy code and update endpoints 2023-09-21 00:51:02 +00:00
Ephraim Atta-Duncan
e330e90688 fix: document meta relation with document 2023-09-20 12:54:24 +00:00
Ephraim Atta-Duncan
f2d3c51651 fix: avoid creating document meta with empty strings 2023-09-20 12:38:39 +00:00
Ephraim Atta-Duncan
c9c111cdf2 fix: persist newline in emails 2023-09-20 12:19:52 +00:00
Lucas Smith
c247295131 Merge pull request #388 from captain-Akshay/feat/theme
feat: added a better theme change ability for user
2023-09-20 21:45:45 +10:00
Ephraim Atta-Duncan
d417255910 feat: replace template variables with values
Co-authored-by: Mythie <me@lucasjamessmith.me>
2023-09-20 11:17:26 +00:00
Ephraim Atta-Duncan
677a15327b feat: send custom email message 2023-09-20 09:59:42 +00:00
Ephraim Atta-Duncan
d5238939ad feat: persist document metadata in database for a specific user 2023-09-20 09:51:04 +00:00
Ephraim Atta-Duncan
6860726e83 feat: send custom email subjects 2023-09-20 09:06:28 +00:00
Ephraim Atta-Duncan
a55197fb2d feat: add prisma schema for document meta 2023-09-20 08:57:50 +00:00
David Nguyen
7eed5c7c96 feat: utilise transport layer 2023-09-20 15:55:25 +10:00
David Nguyen
1c629af651 fix: timeout issues 2023-09-20 15:33:01 +10:00
David Nguyen
4b8aa3298b feat: add single player mode 2023-09-20 13:48:30 +10:00
Lucas Smith
bcb163693a Merge branch 'feat/refresh' into feat/completed-share-link 2023-09-20 12:42:30 +10:00
Lucas Smith
e6e8de62c8 Merge pull request #306 from adithyaakrishna/feat/reveal-password
feat: added feature to show/hide password
2023-09-20 12:38:09 +10:00
Mythie
71c7a6ee8c chore: add visibility toggle to reset password 2023-09-20 02:32:06 +00:00
Mythie
ecc8e59c8c fix: update colors 2023-09-20 02:18:35 +00:00
Lucas Smith
d0f027c4ea Merge branch 'feat/refresh' into feat/reveal-password 2023-09-20 12:13:31 +10:00
Lucas Smith
2c667f785c Merge pull request #385 from documenso/feat/reset-password
feat: reset password
2023-09-20 12:12:57 +10:00
Lucas Smith
1adf7e183e Merge branch 'feat/refresh' into feat/reveal-password 2023-09-20 12:03:24 +10:00
captain-Akshay
7771d7acbe feat: added the icon for theme 2023-09-20 06:56:40 +05:30
Lucas Smith
58580c7fac Merge pull request #386 from documenso/blog/selfhosting-blog-post
feat: add deploying documenso with vercel, supabase and resend
2023-09-20 09:41:41 +10:00
captain-Akshay
4cd56fa98c feat: removed unecessary code to the file and made few UI changes 2023-09-19 19:45:21 +05:30
Lucas Smith
68020006b4 Merge branch 'feat/refresh' into feat/reset-password 2023-09-20 00:03:46 +10:00
Mythie
70cb65d266 fix: update token validity check 2023-09-19 13:59:19 +00:00
Mythie
cef8cad14c fix: update reset token query 2023-09-19 13:57:11 +00:00
Mythie
def8f45f8b fix: update email template 2023-09-19 13:49:01 +00:00
Mythie
ca325cc90b fix: add layout and minor updates 2023-09-19 13:34:54 +00:00
captain-Akshay
a1ce6f696a feat: added a better theme change ability for user 2023-09-19 13:38:37 +05:30
Mythie
09c7f9dde8 chore: update devcontainer 2023-09-19 15:10:03 +10:00
Lucas Smith
0060b9da8c Merge branch 'feat/refresh' into feat/reset-password 2023-09-19 13:53:38 +10:00
Lucas Smith
bad88a2a83 Merge pull request #387 from nsylke/nsylke-patch-9
feat: security headers
2023-09-19 13:51:57 +10:00
Lucas Smith
96a79b8879 Merge branch 'feat/refresh' into nsylke-patch-9 2023-09-19 13:41:18 +10:00
Mythie
60ef9df721 chore: update ci 2023-09-19 13:34:38 +10:00
Lucas Smith
2d8ca8fea0 Merge pull request #374 from documenso/feat/vercel-build-script
feat: vercel build script
2023-09-19 13:11:49 +10:00
Mythie
b411db40da chore: tidy unused code 2023-09-19 02:40:58 +00:00
David Nguyen
1be0b9e01f feat: add vercel build script 2023-09-19 01:54:20 +00:00
nsylke
d41ca8e0e6 feat: security headers 2023-09-18 20:13:46 -05:00
Timur Ercan
eaa3e0a303 Merge branch 'feat/refresh' into feat/mania 2023-09-18 20:15:50 +02:00
Timur Ercan
a283c88d7f chore: update malfunction mania image 2023-09-18 20:11:27 +02:00
Ephraim Atta-Duncan
d4659eee07 feat: add deploying documenso with vercel, supabase and resend 2023-09-18 17:58:01 +00:00
Ephraim Atta-Duncan
b93e3c0b52 feat: add invalid reset token page 2023-09-18 15:13:19 +00:00
Ephraim Atta-Duncan
079963cde8 feat: better error handling and better toast messages 2023-09-18 15:09:41 +00:00
Ephraim Atta-Duncan
45f447c796 feat: better error handling in forgotPassword trpc router 2023-09-18 14:41:24 +00:00
Ephraim Atta-Duncan
2327b15e0d fix: width reducing with screen size 2023-09-18 14:39:42 +00:00
Ephraim Atta-Duncan
166cbc150f feat: send email to user on successful password reset 2023-09-18 14:31:04 +00:00
Ephraim Atta-Duncan
f561ef3cda feat: add reset functionality 2023-09-18 14:03:33 +00:00
Ephraim Atta-Duncan
29bd4cb9c3 feat: send forgot password email 2023-09-18 12:14:55 +00:00
Ephraim Atta-Duncan
1237944b71 chore: rename email templates export 2023-09-18 11:51:43 +00:00
Ephraim Atta-Duncan
b331e3c780 feat: add reset password email template 2023-09-18 11:49:37 +00:00
Ephraim Atta-Duncan
7f641e3e73 feat: add forgot password template 2023-09-18 11:38:02 +00:00
Ephraim Atta-Duncan
b84f0548d2 feat: create a password reset token 2023-09-18 11:15:29 +00:00
Ephraim Atta-Duncan
0f92534f00 chore: remove unused error toast 2023-09-18 10:34:15 +00:00
Ephraim Atta-Duncan
7a489f241a feat: add reset password page 2023-09-18 10:31:33 +00:00
Ephraim Atta-Duncan
f88e529111 feat: add forgot passoword page 2023-09-18 10:18:33 +00:00
Ephraim Atta-Duncan
47d55a5eab feat: add password reset token to schema 2023-09-18 06:47:03 +00:00
Ephraim Atta-Duncan
9dcab76cd5 feat: use description of each blog post in og image (#380) 2023-09-18 11:37:17 +10:00
Ephraim Atta-Duncan
c2a9647c90 Merge branch 'feat/refresh' into feat/redirect-signed-document 2023-09-17 14:52:44 +00:00
Ephraim Atta-Duncan
02424596db fix: update for code review 2023-09-17 14:45:22 +00:00
Ephraim Atta-Duncan
776324c875 fix: fitler only unsigned documents 2023-09-17 14:38:39 +00:00
Ephraim Atta-Duncan
6f4c280583 chore: match file name and method name 2023-09-17 14:31:44 +00:00
Lucas Smith
dfebdfccda Merge pull request #357 from documenso/feat/universal-upload
feat: universal upload
2023-09-16 15:35:30 +10:00
Timur Ercan
5809109c05 chore: grammerly, finetuned bounties 2023-09-14 15:43:17 +02:00
Timur Ercan
a6400eb6c9 Merge branch 'feat/refresh' into feat/mania 2023-09-14 15:29:55 +02:00
flō
39958ed22c Fix typo 2023-09-14 14:57:11 +02:00
Lucas Smith
c3d9cac43f Merge pull request #373 from documenso/chore/readme
chore: update readme to main version
2023-09-14 20:35:21 +10:00
Lucas Smith
74355244a4 Merge pull request #372 from documenso/chore/blogposts
chore: moved rewrite article from next repo
2023-09-14 20:34:55 +10:00
flō
7c4ba1b1ea Fix typo 2023-09-14 11:38:42 +02:00
flō
f588897531 Fix punctuation for consistency 2023-09-14 11:33:11 +02:00
flō
5629e08f83 Add keywords
added keywords in description for SEO optimizations
2023-09-14 11:06:48 +02:00
flō
37394c054c Fix typo
Fix typo and minor edits for consistency
2023-09-14 11:04:10 +02:00
Mythie
8be52e2fa3 fix: final reference to created column 2023-09-14 14:50:17 +10:00
Mythie
0d702e9189 fix: remove further references to created column 2023-09-14 13:37:38 +10:00
Mythie
425db8fc1f fix: remove references to created column 2023-09-14 13:32:16 +10:00
Mythie
2356f58e7b fix: implement feedback 2023-09-14 13:21:03 +10:00
Mythie
6c12ed4afc fix: update migration for timestamp columns 2023-09-14 13:07:55 +10:00
Lucas Smith
d76ee7f33c Merge branch 'feat/refresh' into feat/universal-upload 2023-09-14 12:53:58 +10:00
Mythie
f8534b2c3d fix: add dashboard header border on scroll 2023-09-14 12:51:59 +10:00
Mythie
9014f01276 feat: universal upload
Implementation of a universal upload allowing for multiple storage backends
starting with `database` and `s3`.

Allows clients to put and retrieve files from either client or server using
a blend of client and server actions.
2023-09-14 12:47:47 +10:00
Timur Ercan
71818c0f1f chore: update readme to main version 2023-09-13 14:57:22 +02:00
Timur Ercan
974dc74073 chore: moved rewrite article from next repo 2023-09-13 14:53:27 +02:00
Timur Ercan
b255eb21e5 Merge pull request #369 from documenso/fix/building-documenso-description
fix: update building documenso article description
2023-09-13 14:45:24 +02:00
Timur Ercan
9a58178ea5 Merge branch 'feat/refresh' into fix/building-documenso-description 2023-09-13 14:42:41 +02:00
Timur Ercan
3c36eedfba chore: phrasing 2023-09-13 14:42:27 +02:00
Timur Ercan
46dfaa70a3 Update apps/marketing/content/blog/building-documenso-pt1.mdx
Co-authored-by: Adithya Krishna  <aadithya794@gmail.com>
2023-09-13 14:39:01 +02:00
Lucas Smith
61da354a48 Merge pull request #361 from documenso/feat/admin-ui-metrics
feat: admin ui for metrics
2023-09-13 21:55:09 +10:00
Lucas Smith
fbb332fb35 Merge branch 'feat/refresh' into feat/admin-ui-metrics 2023-09-13 21:54:33 +10:00
Lucas Smith
7e1cce9155 Merge pull request #365 from documenso/feat/avatar-fallback
feat: add avatar email fallback
2023-09-13 21:51:42 +10:00
Lucas Smith
ed4cbe9fa6 Merge branch 'feat/refresh' into feat/universal-upload 2023-09-12 20:51:31 +10:00
Mythie
599e857a1e fix: add removed layout guard 2023-09-12 17:53:38 +10:00
Lucas Smith
581f08c59b fix: update layout and wording 2023-09-12 07:25:44 +00:00
David Nguyen
24a2e9e6d4 feat: update document table layout (#371)
* feat: update document table layout

- Removed dashboard page
- Removed redundant ID column
- Moved date to first column
- Added estimated locales for SSR dates
2023-09-12 14:29:27 +10:00
David Nguyen
e8796a7d86 refactor: organise recipient utils 2023-09-12 12:33:04 +10:00
Mythie
db3f75c42f fix: data table links for recipients 2023-09-12 10:38:23 +10:00
Timur Ercan
b7c0df67b1 feat: malfunction mania, first draft 2023-09-11 18:20:17 +02:00
Timur Ercan
e8b5b3b24a fix: update building documenso article description 2023-09-11 15:22:09 +02:00
Catalin Pit
00574325b9 chore: implemented feedback 2023-09-11 13:43:17 +03:00
Catalin Pit
99706e0ed6 chore: fix version in nextjs config 2023-09-11 11:34:10 +03:00
Catalin Pit
326743d8a1 chore: added app version 2023-09-11 10:59:50 +03:00
David Nguyen
3f67b0f27e Merge pull request #292 from documenso/feat/blog-post-next
fix: typo in blog post
2023-09-11 17:09:31 +10:00
flō
24036b0f24 fix typo 2023-09-11 17:03:14 +10:00
David Nguyen
fbf32404a6 feat: add avatar email fallback 2023-09-11 16:58:41 +10:00
Lucas Smith
975d52a07e Merge pull request #362 from documenso/fix/hide-user-selection
fix: hide popover when user selects a recipient
2023-09-11 12:27:50 +10:00
Ephraim Atta-Duncan
f8a193c0f8 refactor: replace whole implementation with a state 2023-09-09 10:56:45 +00:00
Ephraim Atta-Duncan
9186cb4d7b fix: hide popover when user selects a recipients 2023-09-09 10:42:03 +00:00
Lucas Smith
898f5a629c Merge branch 'feat/refresh' into feat/admin-ui-metrics 2023-09-09 15:49:56 +10:00
Mythie
933076fa3f fix: update devcontainer 2023-09-09 15:49:40 +10:00
Lucas Smith
27edcebef6 Merge branch 'feat/refresh' into feat/admin-ui-metrics 2023-09-09 15:44:34 +10:00
Mythie
abc91f7eac fix: update devcontainer 2023-09-09 15:44:10 +10:00
Lucas Smith
5862af3034 Merge branch 'feat/refresh' into feat/admin-ui-metrics 2023-09-09 15:16:03 +10:00
Mythie
35acf05997 feat: add devcontainer 2023-09-09 04:38:37 +00:00
Lucas Smith
2bad1b9f55 fix: tidy messaging 2023-09-09 03:45:15 +00:00
Lucas Smith
73b0dc315e fix: use ts-pattern 2023-09-09 03:31:17 +00:00
Catalin Pit
5969f148c8 chore: changed the cards titles 2023-09-08 14:51:55 +03:00
Catalin Pit
660f5894a6 chore: feedback improvements 2023-09-08 12:56:44 +03:00
Catalin Pit
77058220a8 chore: rename files 2023-09-08 12:42:14 +03:00
Catalin Pit
6cdba45396 chore: implemented feedback 2023-09-08 12:39:13 +03:00
Catalin Pit
67571158e8 feat: add the admin page 2023-09-08 11:28:50 +03:00
Catalin Pit
171a5ba4ee feat: creating the admin ui for metrics 2023-09-08 09:16:31 +03:00
Ephraim Atta-Duncan
525ff21563 feat: avoid sending pending email to document with 1 recipients 2023-09-07 20:52:18 +00:00
Ephraim Atta-Duncan
863e53a2d5 refactor: pass document id as arguments 2023-09-07 20:38:18 +00:00
Ephraim Atta-Duncan
da2033692c feat: send email when all recipients have signed 2023-09-07 20:14:04 +00:00
Ephraim Atta-Duncan
dbbe17a0a8 feat: send email when recipient is done signing 2023-09-07 19:58:48 +00:00
Mythie
a2ef9468ae feat: separate document data from document 2023-09-07 19:27:21 +10:00
Ephraim Atta-Duncan
0c145fab0b chore: fix eslint errors 2023-09-06 12:01:30 +00:00
Ephraim Atta-Duncan
f6e49e3f21 chore: remove code from different branch 2023-09-06 12:00:23 +00:00
Ephraim Atta-Duncan
1f027d75d3 chore: fix eslint errors 2023-09-06 11:55:02 +00:00
Ephraim Atta-Duncan
1ba7767f8e chore: correct types on component 2023-09-06 11:52:15 +00:00
Ephraim Atta-Duncan
8220b2f086 feat: add empty state for different status 2023-09-06 11:47:58 +00:00
Ephraim Atta-Duncan
a74374e39f feat: add initial empty state for no results 2023-09-06 11:11:13 +00:00
Lucas Smith
ff957a2f82 Merge pull request #353 from documenso/feat/disable-sign
feat: disable signing and editing for completed documents
2023-09-06 20:53:23 +10:00
Ephraim Atta-Duncan
6640f0496a feat: disable signing and editing for completed documents 2023-09-06 10:40:45 +00:00
Ephraim Atta-Duncan
e47ab838c5 chore: remove undefined check 2023-09-06 07:37:03 +00:00
Ephraim Atta-Duncan
551918ab9b feat: redirect signed document to completed page 2023-09-05 13:53:18 +00:00
Ephraim Atta-Duncan
739f3763dd feat: update share page to match latest changes 2023-09-05 11:40:42 +00:00
Ephraim Atta-Duncan
0cdd980a4b feat: move opengraph-image to next.js 13 implementation 2023-09-05 11:37:21 +00:00
Ephraim Atta-Duncan
b43ddcbea2 refactor: redirect using useRouter 2023-09-05 09:29:47 +00:00
Ephraim Atta-Duncan
75feaefbf2 chore: remove unused files 2023-09-05 09:27:04 +00:00
Lucas Smith
de3ebe16ee Merge pull request #349 from documenso/feat/marketing-mobile-nav
feat: update marketing mobile nav
2023-09-05 18:20:53 +10:00
David Nguyen
84a2d3baf6 feat: update marketing mobile menu 2023-09-05 18:08:29 +10:00
Lucas Smith
74180defd1 Merge pull request #339 from G3root/feat-api-error
feat: add alert banner for errors in sigin page
2023-09-05 15:36:55 +10:00
Lucas Smith
aeeaaf0d8d Merge pull request #340 from G3root/fix-username-updateable
fix: user name not updatable
2023-09-05 15:33:19 +10:00
Lucas Smith
2b84293c4e Merge pull request #341 from documenso/feat/add-email-field
feat: add email field to document sign page
2023-09-05 13:25:29 +10:00
Lucas Smith
b38ef6c0a7 Merge pull request #346 from documenso/chore/remove-console-log-warn
chore: removed console logs and warn
2023-09-05 13:23:57 +10:00
Mythie
d524ea77ab fix: update styling 2023-09-05 13:15:45 +10:00
Mythie
17af4d25bd fix: actually make timeouts clear 2023-09-05 11:33:49 +10:00
Mythie
6e095921e6 fix: tidy up code 2023-09-05 11:29:23 +10:00
nafees nazik
150c42b246 fix: value 2023-09-04 22:24:42 +05:30
Catalin Pit
aecf2f32b9 chore: removed one more console.log 2023-09-04 16:41:28 +03:00
Catalin Pit
b23967d777 chore: removed console.logs and warn 2023-09-04 16:08:22 +03:00
Adithya Krishna
2524458b0c chore: updated wording
Signed-off-by: Adithya Krishna <aadithya794@gmail.com>
2023-09-03 23:59:02 +05:30
Adithya Krishna
12c45fb882 feat: added 404 page for web app
Signed-off-by: Adithya Krishna <aadithya794@gmail.com>
2023-09-03 23:53:07 +05:30
Adithya Krishna
118483b6cc chore: updated 404 page for marketing app
Signed-off-by: Adithya Krishna <aadithya794@gmail.com>
2023-09-03 23:52:51 +05:30
Adithya Krishna
fd6350b397 feat: added 404 page for marketing app
Signed-off-by: Adithya Krishna <aadithya794@gmail.com>
2023-09-03 23:30:48 +05:30
Ephraim Atta-Duncan
b3291c65bc chore: remove console.log 2023-09-02 22:20:57 +00:00
Ephraim Atta-Duncan
4b849e286c feat: add missing email field to document sign page 2023-09-02 22:08:19 +00:00
nafees nazik
7bcc26a987 fix: user name not updatable 2023-09-02 12:11:07 +05:30
nafees nazik
692722d32e revert: fix: component style 2023-09-02 11:55:44 +05:30
Nafees Nazik
e4f06d8e30 Merge branch 'feat/refresh' into feat-api-error 2023-09-02 11:53:18 +05:30
nafees nazik
c799380787 chore: add comments 2023-09-02 11:51:21 +05:30
nafees nazik
5540fcf0d2 fix: use toast 2023-09-02 11:46:12 +05:30
nafees nazik
d9da09c1e7 fix: typo 2023-09-01 16:25:49 +05:30
nafees nazik
fe90aa3b7b feat: add api error 2023-09-01 16:25:27 +05:30
nafees nazik
0c680e0111 fix: component style 2023-09-01 16:25:00 +05:30
Mythie
7bcf5fbd86 feat: store signature on signup 2023-09-01 19:46:44 +10:00
Mythie
7218b950fe feat: store profile signature 2023-09-01 18:43:53 +10:00
Mythie
8d4df7d3dd fix: update og card 2023-08-31 15:36:09 +10:00
Lucas Smith
f1f6e2e40a Merge branch 'feat/refresh' into feat/completed-share-link 2023-08-31 14:20:52 +10:00
Lucas Smith
901013fdc6 Merge pull request #313 from adithyaakrishna/feat/improve-readability
feat: improve readability and rendering of some components
2023-08-31 14:08:52 +10:00
Lucas Smith
5c9017f3cd Merge branch 'feat/refresh' into feat/improve-readability 2023-08-31 14:06:43 +10:00
Mythie
34e962cc48 fix: minor updates 2023-08-31 14:06:19 +10:00
Lucas Smith
bf9254597a Merge pull request #321 from PeterKwesiAnsah/feat/Add-error-message-to-signature-pad
feat: add error message to signature pad
2023-08-31 13:59:41 +10:00
Mythie
b5efa0d3ea fix: fix eslint warnings 2023-08-31 13:33:13 +10:00
Lucas Smith
a2bdb46076 Merge pull request #333 from documenso/fix/redirect-signin-to-dashboard
fix: redirect signin page to dashboard when logged in
2023-08-31 13:14:52 +10:00
Lucas Smith
ed150d9574 Merge branch 'feat/refresh' into fix/redirect-signin-to-dashboard 2023-08-31 13:14:07 +10:00
Mythie
e756a21fda fix: retain redirect to documents rather than dashboard 2023-08-31 13:12:50 +10:00
Lucas Smith
13084049da Merge pull request #334 from documenso/feat/redirect-on-send
feat: redirect to dashboard when document is sent
2023-08-31 13:09:55 +10:00
Lucas Smith
055e723777 Merge pull request #335 from adithyaakrishna/chore/remove-cl
chore: removed unnecessary `console.log`
2023-08-31 13:09:03 +10:00
Lucas Smith
419318c151 Merge pull request #329 from documenso/feat/blog-og-image
feat: add blog og image
2023-08-31 13:04:15 +10:00
Mythie
7722e63e1b fix: tidying broke generation 2023-08-31 12:08:53 +10:00
Adithya Krishna
40274021ba Merge branch 'feat/refresh' into feat/reveal-password 2023-08-30 20:34:32 +05:30
Adithya Krishna
8529ac3ffe Merge branch 'feat/refresh' into feat/improve-readability 2023-08-30 20:34:08 +05:30
Adithya Krishna
7ec8e762b0 chore: removed console logs
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-30 18:49:13 +05:30
Ephraim Atta-Duncan
2acada6dc7 chore: unused console logs 2023-08-30 13:09:37 +00:00
Ephraim Atta-Duncan
d4d76dce03 feat: redirect to dashboard when document is sent 2023-08-30 12:31:33 +00:00
Ephraim Atta-Duncan
3832ce2c80 fix: redirect root direcotory to dashboard 2023-08-30 11:32:55 +00:00
Ephraim Atta-Duncan
fd36e39a38 fix: redirect signin page to dashboard when logged in 2023-08-30 11:32:08 +00:00
Mythie
14fd0eb906 fix: tidy code and expect jsx errors 2023-08-30 18:41:37 +10:00
Lucas Smith
af6c62d0bf Merge branch 'feat/refresh' into feat/blog-og-image 2023-08-30 18:28:21 +10:00
Mythie
8d7d6a19e7 fix: update import for feature-flag helpers 2023-08-30 18:06:41 +10:00
Mythie
463dc48ea6 fix: extract feature-flag zod schema to separate file 2023-08-30 17:31:23 +10:00
Lucas Smith
d8f6a25059 Merge pull request #332 from documenso/feat/billing-page
feat: make billing page functional
2023-08-30 16:41:39 +10:00
Mythie
93962625ed fix: further stash conflicts 2023-08-30 16:39:35 +10:00
Mythie
249211bd4f fix: add items from stash 2023-08-30 16:36:22 +10:00
Mythie
bfe0d50661 feat: make billing page functional 2023-08-30 16:15:13 +10:00
Mythie
5d4a07bcc5 fix: center align heading 2023-08-30 15:41:29 +10:00
Mythie
d28bb5de99 fix: use nextjs opengraph-image component 2023-08-30 15:32:44 +10:00
Lucas Smith
83a83164d4 Merge pull request #330 from documenso/feat/profile-password-form
feat: avoid user from updating password with the same password
2023-08-30 14:32:21 +10:00
Mythie
d71e43c5d6 fix: minor tidying 2023-08-30 14:01:30 +10:00
Ephraim Atta-Duncan
ed6fa4dc2a feat: avoid updating password with existing password 2023-08-30 03:26:24 +00:00
Ephraim Atta-Duncan
4f3970c361 feat: prevent a user from updating password with the same password 2023-08-30 03:22:47 +00:00
Ephraim Atta-Duncan
40767430d9 feat: reset password from on submit 2023-08-30 03:09:40 +00:00
Ephraim Atta-Duncan
1edfe9548d feat: add og image to blog posts 2023-08-30 02:50:02 +00:00
Lucas Smith
fead48c2f0 Merge pull request #314 from adithyaakrishna/fix/whitespace
fix: removed unnecessary whitespace before className
2023-08-30 12:36:58 +10:00
Mythie
0abd3da7fd fix: update eslint rules 2023-08-30 12:35:43 +10:00
Ephraim Atta-Duncan
2f78922421 feat: add blog og image 2023-08-30 02:33:22 +00:00
Lucas Smith
3df0f61947 Merge branch 'feat/refresh' into fix/whitespace 2023-08-30 12:02:01 +10:00
Lucas Smith
8e42dcb7ee Merge pull request #323 from documenso/feat/promise-safety
feat: promise safety
2023-08-30 11:32:32 +10:00
Lucas Smith
1888ee97e6 Merge pull request #296 from documenso/feat/inbox
feat: add inbox
2023-08-30 10:27:32 +10:00
Lucas Smith
068aef665d Merge pull request #328 from nsylke/nsylke-patch-8
chore: change root package.json name
2023-08-30 10:10:42 +10:00
nsylke
2772fc1678 chore: change root package.json name 2023-08-29 16:19:56 -05:00
Ephraim Atta-Duncan
66dfdc5ad0 feat: redirect share page to marketing page after 3 seconds 2023-08-29 19:42:37 +00:00
Ephraim Atta-Duncan
b45978374b feat: generate metatags for share page with og image 2023-08-29 19:08:54 +00:00
Ephraim Atta-Duncan
81c3e701e2 feat: display signature text from params 2023-08-29 18:46:15 +00:00
Ephraim Atta-Duncan
874d919a6a feat: create sharing id for each recipient 2023-08-29 18:23:52 +00:00
Ephraim Atta-Duncan
e8559cecd5 feat: add initial og image for share link 2023-08-29 14:39:49 +00:00
Mythie
8c4120f0a2 fix: remove further unused code 2023-08-29 18:12:46 +10:00
Mythie
9f93af6134 fix: remove unused code 2023-08-29 17:26:19 +10:00
Adithya Krishna
3cbc722b94 Merge branch 'feat/refresh' into feat/reveal-password 2023-08-29 12:43:46 +05:30
Adithya Krishna
3440c47c3c Merge branch 'feat/refresh' into feat/improve-readability 2023-08-29 12:43:30 +05:30
Mythie
68a5a9da1e feat: add data table actions 2023-08-29 14:33:07 +10:00
Mythie
1f8d5e45e1 feat: onepage inbox 2023-08-29 14:33:05 +10:00
David Nguyen
8fd9730e2b feat: add inbox 2023-08-29 14:31:13 +10:00
Lucas Smith
04f6df6839 Merge pull request #304 from G3root/fix-overscroll
fix: tab overflow on smaller viewport and tab scroll ux
2023-08-29 13:26:26 +10:00
Mythie
ca40e983e3 feat: promise safety with eslint 2023-08-29 13:01:19 +10:00
PeterKwesiAnsah
9257454a96 feat: add error message to signature pad 2023-08-28 14:11:53 +01:00
Lucas Smith
ba054ae915 Merge pull request #319 from documenso/chore/reduce-refetch-time
chore: reduce open page caching time to 1 hour
2023-08-28 22:58:05 +10:00
Ephraim Atta-Duncan
1d1c6e5a55 chore: reduce open page caching time to 1 hour 2023-08-28 09:43:39 +00:00
Adithya Krishna
8844143ff5 chore: fixed conflicts
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 13:02:33 +05:30
Adithya Krishna
c161a8109b fix: removed passHref and updated card
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:58:30 +05:30
Adithya Krishna
e340c4ed6f fix: reverted line change
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:54:55 +05:30
Adithya Krishna
b5f96ee2fc chore: made requested changes - v2
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:53:51 +05:30
Adithya Krishna
3c1790ba83 chore: made requested changes
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:45:23 +05:30
Adithya Krishna
f41c78e8e3 feat: updated rendeing of items using map
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:45:23 +05:30
Adithya Krishna
b8b8b4dbad chore: updated footer component
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:45:22 +05:30
Adithya Krishna
d195dc1a46 chore: updated signing fields
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:45:22 +05:30
Adithya Krishna
3ac29d8da3 chore: updated dashboard page
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:45:22 +05:30
Adithya Krishna
2418612507 chore: updated documents page
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:45:22 +05:30
Adithya Krishna
e8336ae9b4 chore: removed eslint-plugin-import
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:34:29 +05:30
Adithya Krishna
aad52a3e2e fix: updated eslint config
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:34:29 +05:30
Adithya Krishna
829122c486 feat: added eslint plugin dependencies
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:34:29 +05:30
Adithya Krishna
090752c539 feat: added new eslint rules
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:34:29 +05:30
Adithya Krishna
fad6414995 fix: duplicate import
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:34:29 +05:30
Adithya Krishna
c817c67a1c fix: removed more unnecessary whitespace
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:34:29 +05:30
Adithya Krishna
c7001e62f3 fix: removed unnecessary whitespace
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-28 12:34:29 +05:30
Lucas Smith
bf71d2a14e Merge pull request #305 from G3root/responsive-signing-card
fix: make signing form card responsive
2023-08-28 13:07:46 +10:00
Lucas Smith
163911255e Merge pull request #308 from adithyaakrishna/feat/pr-validate
feat: pr title validator workflow
2023-08-28 12:21:36 +10:00
Lucas Smith
24e38a3bbc Merge pull request #309 from nsylke/nsylke-patch-7
feat: set min/max lengths and autocomplete for password
2023-08-28 12:21:08 +10:00
Lucas Smith
dfd714f16a Merge pull request #310 from adithyaakrishna/feat/add-sharp
feat: added sharp package for NextJS13 image optimizations
2023-08-28 12:19:33 +10:00
Mythie
722081f89e fix: dependency ordering 2023-08-28 12:14:15 +10:00
Lucas Smith
f0e1df22b8 Merge pull request #312 from G3root/fix-auth
fix: authentication allowing any password
2023-08-28 12:04:07 +10:00
nafees nazik
615cb263fb fix: authentication 2023-08-27 07:10:41 +05:30
nafees nazik
18faaf49d9 fix: style 2023-08-27 06:26:49 +05:30
Adithya Krishna
650b69ae56 feat: added sharp for image optimizations on nextjs
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-26 21:23:30 +05:30
Adithya Krishna
eb4be963e3 fix: added eol to workflow file
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-26 20:57:02 +05:30
Adithya Krishna
27c27743e3 chore: updated workflow name
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-26 20:57:02 +05:30
Adithya Krishna
92930a2f63 feat: added pr title validator
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-26 20:57:02 +05:30
nsylke
7ad3365b0e feat: add autocomplete for password managers 2023-08-26 10:22:44 -05:00
Adithya Krishna
7de7624477 fix: update icon sizes
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-26 20:52:07 +05:30
Adithya Krishna
7c6b5ac59d fix: updated padding and set patterns
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-26 20:43:54 +05:30
Adithya Krishna
9c45ce61b8 feat: added show password feature
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-26 20:43:54 +05:30
nsylke
f8bf4fea36 feat: set min/max lengths for password 2023-08-26 09:53:58 -05:00
Lucas Smith
10cd8144eb Merge pull request #307 from adithyaakrishna/feat/optimize-images
chore: optimize images
2023-08-26 20:06:48 +10:00
Adithya Krishna
66973a3745 chore: optimized images to save ~8mb
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-26 13:13:30 +05:30
nafees nazik
85677bb792 fix: make signing form card responsive 2023-08-26 08:47:19 +05:30
nafees nazik
7ae99d2038 fix: overflow and scroll ux 2023-08-26 07:22:51 +05:30
Mythie
70a5105783 fix: add missing await on mail send 2023-08-25 18:33:24 +10:00
Mythie
420372ac9e fix: nicer dark mode for stack avatars 2023-08-25 17:52:58 +10:00
Mythie
6b00282a87 chore: support direct urls for prisma 2023-08-25 17:52:24 +10:00
Lucas Smith
dae1001cbb Merge pull request #300 from documenso/feat/update-document-flow
feat: update document flow
2023-08-25 12:11:43 +10:00
David Nguyen
af81d99b2a refactor: remove whitespace 2023-08-25 11:43:41 +10:00
David Nguyen
2751adc463 feat: update document flow
- Fixed z-index when dragging pre-existing fields
- Refactored document flow
- Added button spinner
- Added animation for document flow slider
- Updated drag and drop fields
- Updated document flow so it adjusts to the height of the PDF
- Updated claim plan dialog
2023-08-25 11:43:41 +10:00
Lucas Smith
396ce9f3f3 Merge pull request #295 from nsylke/nsylke-patch-6
fix: use -p cli option for next dev
2023-08-25 11:29:44 +10:00
Lucas Smith
3f4f66d878 Merge pull request #298 from adithyaakrishna/fix/dependabot
fix: dependabot workflow
2023-08-25 11:28:12 +10:00
Adithya Krishna
d6751d7a26 fix: dependabot workflow
Signed-off-by: Adithya Krishna <aadithya794@gmail.com>
2023-08-24 05:37:17 +00:00
Mythie
0e32baff0b feat: change document view upon completion 2023-08-24 13:31:50 +10:00
nsylke
f76bf4c2c7 fix: use -p cli option for next dev 2023-08-23 17:56:12 -05:00
Lucas Smith
0d8532ab6d Merge pull request #293 from documenso/feat/refactor-shared-components
refactor: extract common components into UI package
2023-08-23 14:08:23 +10:00
Lucas Smith
490d3d51e1 Merge pull request #290 from nsylke/nsylke-patch-5
feat: create robots.txt and sitemap.xml
2023-08-23 13:56:46 +10:00
David Nguyen
2ab796910e refactor: extract common components into UI package 2023-08-23 11:22:13 +10:00
Mythie
07102588be chore: resolve build errors 2023-08-23 10:57:31 +10:00
Nicholas Sylke
04f9422f24 feat: robots.txt & sitemap.xml 2023-08-21 21:41:19 -05:00
Lucas Smith
05a7f5e178 Merge pull request #289 from adithyaakrishna/fix/codeql
fix: fixed build command in codeql workflow
2023-08-22 12:10:45 +10:00
Adithya Krishna
7bae814f96 fix: fixed build command in codeql workflow
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-22 07:26:26 +05:30
Lucas Smith
ea45e38fa0 Merge pull request #273 from documenso/feat/feature-flag
feat: feature flags
2023-08-22 10:13:51 +10:00
Lucas Smith
6d9a85112f Merge pull request #286 from documenso/feat/blog-post-next
feat: add blog post 'Preview the next Documenso'
2023-08-22 10:07:43 +10:00
Lucas Smith
346efd19db Merge pull request #284 from adithyaakrishna/feat/general-updates
feat: added codeql and dependabot workflows
2023-08-22 10:06:39 +10:00
Adithya Krishna
617143a47f fix: removed ts from codeql
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-21 22:42:45 +05:30
flō
66f067276e Add visual asset for blog post 2023-08-21 17:24:29 +02:00
flō
fc10d0449f Create blog post 2023-08-21 17:23:47 +02:00
Adithya Krishna
083f3e7108 feat: add codeql-analysis
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-21 19:08:47 +05:30
Adithya Krishna
af307a2a49 chore: updated dependabot config
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-21 19:03:53 +05:30
Adithya Krishna
b063758ee5 chore: update readme file with radix-ui
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-21 19:03:26 +05:30
Adithya Krishna
4964b252e3 chore: update readme file
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-21 18:56:48 +05:30
Adithya Krishna
e468f5bbc9 chore: enable job concurrency
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-21 18:55:53 +05:30
Adithya Krishna
c5b7b8a18a feat: add dependabot config
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-21 18:54:59 +05:30
Adithya Krishna
a8a1fbb829 feat: Added Engines to Enforce Node v18.0.0 and above
Signed-off-by: Adithya Krishna <adikrish@redhat.com>
2023-08-21 18:54:44 +05:30
Timur Ercan
3c2a4892e7 Merge pull request #283 from documenso/chore/shop
chore: add shop to footer
2023-08-21 14:18:18 +02:00
Timur Ercan
6d9e84d327 chore: add shop to footer 2023-08-21 14:16:19 +02:00
Timur Ercan
73b4e30c97 Merge pull request #257 from documenso/feat/onepage
Feat/onepage
2023-08-21 13:33:04 +02:00
Lucas Smith
bd01545a70 Merge pull request #271 from premiare/feat/mobileNavigation
feat: Mobile Navigation
2023-08-21 20:01:08 +10:00
Mythie
6d360e581d fix: styling updates 2023-08-21 19:56:18 +10:00
David Nguyen
ba95818da4 feat: update items 2023-08-21 12:17:56 +10:00
David Nguyen
d0720f4c70 feat: update items
Refactored billing flag name

Refactored FeatureFlag type

Disabled session recording by default
2023-08-21 12:17:56 +10:00
David Nguyen
f60cb22f11 feat: feature flags 2023-08-21 12:17:56 +10:00
Lucas Smith
e0cb4314fb Merge pull request #280 from nsylke/nsylke-patch-4
chore: ignore intellij editor settings and some of vscode
2023-08-19 10:53:11 +10:00
Nicholas Sylke
0571137a60 chore: ignore intellij editor settings and some of vscode 2023-08-18 18:41:06 -05:00
Timur Ercan
30aabf50eb Merge pull request #279 from documenso/feat/funding
chore: remove funding rounding
2023-08-18 17:50:51 +02:00
Timur Ercan
8441a5eb98 Merge branch 'feat/refresh' into feat/funding 2023-08-18 17:48:31 +02:00
Timur Ercan
259ab49bc1 chore: remove funding rounding 2023-08-18 17:47:36 +02:00
premiare
2f2d5dfc0b Merge branch 'feat/refresh' into feat/mobileNavigation 2023-08-18 19:57:26 +10:00
premiare
0f27f4261b add PORT number back to package.json 2023-08-18 19:37:07 +10:00
premiare
9b92cad2db move menu links to map, add window-size hook 2023-08-18 19:35:45 +10:00
premiare
ad1ff6159c add reducedMotion check, center menu items 2023-08-18 19:05:46 +10:00
Lucas Smith
f633b17f17 Merge pull request #270 from Ashutosh-Bhadauriya/feat/add-commitlint
feat: add commitlint
2023-08-18 18:38:31 +10:00
Ashutosh-Bhadauriya
8fa16001e6 fix: commitlint 2023-08-18 13:49:46 +05:30
Ashutosh-Bhadauriya
e111234460 feat: add commitlint 2023-08-18 13:26:01 +05:30
Lucas Smith
034072f50e Merge branch 'feat/refresh' into feat/onepage 2023-08-18 12:15:36 +10:00
Lucas Smith
a7664d79fd Merge pull request #260 from documenso/feat/document-authoring
feat: document authoring
2023-08-18 12:10:35 +10:00
Lucas Smith
8ed2393300 Merge branch 'feat/refresh' into feat/document-authoring 2023-08-18 12:07:50 +10:00
Lucas Smith
94cf150ffd Merge pull request #258 from nsylke/nsylke-patch-3
ci: create build workflow
2023-08-18 09:32:44 +10:00
Nicholas Sylke
c571a3d0d9 ci: use built-in cache from setup-node action 2023-08-17 18:17:27 -05:00
Lucas Smith
1c7431b859 Merge pull request #264 from documenso/fix/blog-post-pre-seed
Fix: typo in blog post `pre-seed`
2023-08-18 08:59:21 +10:00
Lucas Smith
2f7d6548ef Merge pull request #259 from documenso/feat/pie-chart-legend
feat: add legend to pie chart
2023-08-18 08:55:49 +10:00
flō
a16525be5e fix typo 2023-08-17 17:20:55 +02:00
flō
21e377d3ff fix typo for consistency 2023-08-17 16:46:42 +02:00
premiare
45d0d3f7e8 extract hamburger to own file 2023-08-18 00:18:25 +10:00
premiare
6e62eb8d81 init mobileNavigation and added documenso symbol 2023-08-18 00:12:13 +10:00
Timur Ercan
e098449af4 Merge pull request #262 from documenso/feat/funding
fix: link
2023-08-17 13:02:38 +02:00
Timur Ercan
47d0030cf0 fix: link 2023-08-17 13:02:21 +02:00
Ephraim Atta-Duncan
b564e5e72f feat: reduce chart radius to add padding 2023-08-17 10:57:36 +00:00
Timur Ercan
e46607c1cb Merge pull request #261 from documenso/feat/funding
Feat/funding
2023-08-17 12:56:04 +02:00
Timur Ercan
77c5db169a fix: format heade 2023-08-17 12:54:40 +02:00
Timur Ercan
0157bf9576 chore: adding open to footer, naming 2023-08-17 12:50:31 +02:00
Timur Ercan
454c2f45bd fix: open page link 2023-08-17 12:46:24 +02:00
Timur Ercan
badb897c06 chore: update date 2023-08-17 12:41:55 +02:00
Timur Ercan
9bb5768598 Merge branch 'feat/refresh' into feat/funding 2023-08-17 12:39:37 +02:00
Timur Ercan
951de8baf5 chore: review updates 2023-08-17 12:37:58 +02:00
Mythie
48ceb1e5c7 feat: document authoring 2023-08-17 19:56:18 +10:00
Ephraim Atta-Duncan
96e8962956 feat: change legend text color to black 2023-08-17 09:44:43 +00:00
Ephraim Atta-Duncan
f3259aedea feat: Add legend to pie chart 2023-08-17 08:24:37 +00:00
Lucas Smith
9fdc9dcbf7 Merge pull request #256 from nsylke/nsylke-patch-2
Add husky & lint staged
2023-08-17 11:07:18 +10:00
Nicholas Sylke
0a30403719 ci: remove --workspaces from the build script in ci workflow 2023-08-16 20:00:13 -05:00
Nicholas Sylke
0e1fcd86e6 ci: setup build workflow 2023-08-16 19:51:45 -05:00
Nicholas Sylke
8038f3ad00 fix: used wrong lockfile version when resolving conflicts 2023-08-16 13:00:50 -05:00
Timur Ercan
44369ee7f6 mention cals open startup article 2023-08-16 17:52:04 +02:00
Timur Ercan
7e46cb0d8e feat: pre seed announce and link on /open page 2023-08-16 17:42:27 +02:00
Nicholas Sylke
10e39246ce Merge branch 'feat/refresh' into nsylke-patch-2
# Conflicts:
#	package-lock.json
2023-08-16 07:34:40 -05:00
Timur Ercan
5e45767e44 Merge pull request #249 from documenso/feat/open-page
feat: add cap table to open page
2023-08-16 14:09:01 +02:00
Timur Ercan
61d7f7cbcd chore: whitespace 2023-08-16 14:08:21 +02:00
Timur Ercan
8f3c47d659 Merge branch 'feat/refresh' into feat/open-page 2023-08-16 14:05:18 +02:00
Timur Ercan
3b9c57fe5c chore: remove double emtpy state add CTA 2023-08-16 13:49:19 +02:00
Nicholas Sylke
6017d35cfd refactor: future proofing the prettier/lint-staged for js/ts filetypes 2023-08-16 06:27:45 -05:00
Timur Ercan
90e28cd3a4 chore: status order to figma 2023-08-16 09:29:16 +02:00
Timur Ercan
e743e56787 remove dashboard and link bar 2023-08-16 09:03:28 +02:00
Nicholas Sylke
ba25ea1370 refactor: use lint-staged.config.cjs as configuration for lint-staged 2023-08-15 16:02:58 -05:00
Ephraim Atta-Duncan
b7543298e1 fix: ssr hydration error in piechart 2023-08-15 18:02:10 +00:00
Timur Ercan
29b4cb7793 chore: add total 2023-08-15 14:00:05 +02:00
Ephraim Atta-Duncan
f7c3190346 chore: fix ts errors in metrics 2023-08-15 11:13:13 +00:00
Ephraim Atta-Duncan
5130dc5f31 chore: refactor github charts into a single component 2023-08-15 09:43:24 +00:00
Ephraim Atta-Duncan
d3cdd2c317 chore: use correct names on tooltip 2023-08-15 09:17:51 +00:00
Ephraim Atta-Duncan
96f7ca4e36 feat: add other charts 2023-08-15 08:45:24 +00:00
Ephraim Atta-Duncan
e2471a8eb4 chore: fix eslint error in data 2023-08-14 22:03:56 +00:00
Ephraim Atta-Duncan
5f33b1da1e chore: format date 2023-08-14 22:01:25 +00:00
Ephraim Atta-Duncan
bca048c026 chore: fetch stargazers data from stargazers api 2023-08-14 21:51:38 +00:00
Ephraim Atta-Duncan
f999ca48f6 feat: add github stars cummulative 2023-08-14 21:33:16 +00:00
Nicholas Sylke
f0c607d87a add husky and lint-staged to ensure commits are formatted 2023-08-14 16:14:53 -05:00
Timur Ercan
6f394138f5 chore: team updates, funding cummulative 2023-08-14 14:16:04 +02:00
Ephraim Atta-Duncan
b710693009 feat: add team members engagement to open page 2023-08-08 01:53:56 +00:00
Lucas Smith
fb4b96a838 Merge pull request #246 from fmerian/feat/refresh
Edit blog post
2023-08-07 11:24:36 +10:00
Ephraim Atta-Duncan
af2dae8822 --amend 2023-08-06 23:01:33 +00:00
Ephraim Atta-Duncan
e400dbe2ea feat: add tooltip to cap table 2023-08-06 22:59:09 +00:00
Ephraim Atta-Duncan
b718bdeb15 Add initial cap table 2023-08-06 22:46:20 +00:00
Mythie
9ca84f5ede chore: add contributor license agreement 2023-08-05 17:44:39 +10:00
flō
1a31cc321c fix typo 2023-08-04 08:25:51 +02:00
flō
2ec3cebcc9 Optimize description 2023-08-03 12:32:27 +02:00
flō
659af87592 Edit content 2023-08-03 11:40:00 +02:00
Lucas Smith
beb1a4c214 Merge pull request #243 from fmerian/feat/refresh
Add new blog post: Switching to Discord
2023-08-02 20:09:01 +10:00
flō
16a7030922 Edit blog post description 2023-08-02 11:27:07 +02:00
flō
c036858d45 Update link to community (Discord) 2023-08-02 11:16:04 +02:00
flō
84d295e324 Update link to community (Discord) 2023-08-02 11:15:08 +02:00
flō
90eb54f768 Add blog post: Switching to Discord 2023-08-02 11:11:29 +02:00
flō
547ed337a6 Add profile picture: Flo 2023-08-02 10:57:29 +02:00
Lucas Smith
3f5937717f Merge pull request #238 from fmerian/fix-blog
Update blog
2023-08-02 17:52:17 +10:00
flō
3cdfde5e0f fix mailto 2023-08-02 09:07:34 +02:00
Ephraim Atta-Duncan
6b1fcb8193 feat: open page 2023-08-01 17:43:11 +10:00
Mythie
9431e7f0ad chore: upgrade deps and linting 2023-08-01 17:34:17 +10:00
flō
817569a333 fix typo 2023-07-31 11:26:43 +02:00
flō
0bbaa64080 edit announcing-documenso.mdx
- fix typo for consistency in tone and voice
- edit filename for SEO
2023-07-31 10:39:05 +02:00
flō
c403812389 edit manifest.mdx
- fix typo in caption for consistency
- edit filename (URL) for SEO
2023-07-31 10:26:30 +02:00
Lucas Smith
25d7390b27 Merge pull request #207 from doug-andrade/v2-google-auth
feat: add google as auth provider  **no schema change**
2023-07-31 13:55:25 +10:00
Mythie
918018c7ca fix: improve typesafety 2023-07-31 13:53:55 +10:00
Mythie
58baf5ddf4 Merge branch 'feat/refresh' into v2-google-auth 2023-07-31 13:03:32 +10:00
Mythie
32dcd4aa0e chore: add oss friends page 2023-07-29 17:39:08 +10:00
Lucas Smith
cacfc2c535 Merge pull request #236 from documenso/feat/content-layer
feat: add content layer
2023-07-29 00:25:26 +10:00
Mythie
8115ea3bf2 fix: type errors 2023-07-28 20:16:06 +10:00
Mythie
c64ff8ec95 fix: styling updates 2023-07-28 20:14:04 +10:00
David Nguyen
38323b5ea5 feat: update privacy content 2023-07-28 16:31:10 +10:00
David Nguyen
34d10bd313 feat: update blog styling 2023-07-28 11:19:52 +10:00
David Nguyen
d743f8411a feat: update privacy content 2023-07-28 11:07:01 +10:00
David Nguyen
d8a6aa2686 feat: remove whitespace 2023-07-28 10:54:03 +10:00
David Nguyen
dfcfe1d8d2 feat: add generic content page 2023-07-28 09:58:47 +10:00
David Nguyen
6038c3cc78 Update apps/marketing/content/blog/announcing-documenso.mdx
Co-authored-by: Joshua Sharp <joshuafsharp@gmail.com>
2023-07-28 09:12:37 +10:00
David Nguyen
97efcf3d62 feat: add content layer
Add blog pages

Add privacy page
2023-07-27 18:29:22 +10:00
Lucas Smith
889ad1c49f Merge pull request #217 from documenso/feat/stacked-avatars
feat: stack avatars
2023-07-26 19:58:34 +10:00
Mythie
b3fa837967 feat: use server-actions for authoring flow
This change actually makes the authoring flow work for
the most part by tying in emailing and more.

We have also done a number of quality of life updates to
simplify the codebase overall making it easier to continue
work on the refresh.
2023-07-26 18:52:53 +10:00
Ephraim Atta-Duncan
a5334ca6e6 refactor: read z-index values from an object 2023-07-05 20:47:12 +00:00
Ephraim Atta-Duncan
0ad0524157 Merge branch 'feat/refresh' into feat/stacked-avatars 2023-07-01 01:16:58 +00:00
Ephraim Atta-Duncan
b50f64d4ad fix: update types from code review 2023-06-30 23:49:34 +00:00
Ephraim Atta-Duncan
88d15376e3 feat: update stack avatar with changes from code review 2023-06-30 23:38:37 +00:00
Ephraim Atta-Duncan
aa884310eb feat: add recipients avatars on all tables 2023-06-25 15:14:48 +00:00
Ephraim Atta-Duncan
dbcf7771b9 chore: refactor stacked avatars into component 2023-06-25 14:23:18 +00:00
Mythie
60b150cc58 fix: add shadow to metric-card 2023-06-24 15:01:18 +10:00
Mythie
bd0db0f8fd feat: email templates
adds email templates using `react-email` which will be used for invites,
signing and document completion.

authored by @dephraiim
2023-06-24 14:59:08 +10:00
Ephraim Atta-Duncan
2e8e39c5a9 feat: add tooltip on hover on stacked avatars 2023-06-23 20:19:25 +00:00
Ephraim Atta-Duncan
f22baca569 feat: stack recipients avatars on dashboard 2023-06-23 12:20:49 +00:00
Mythie
d8a094a324 chore: use jsonprotocol 2023-06-23 18:06:02 +10:00
Lucas Smith
4b063b68ab Merge pull request #214 from doug-andrade/refresh/dashboard-filters
linking card metrics to filtered /documents
2023-06-22 08:09:16 +10:00
Doug Andrade
3c02331cb9 linking card metrics to filtered /documents 2023-06-21 17:57:02 -04:00
Mythie
eea09dcfac feat: persist fields and recipients for document editing 2023-06-21 23:49:23 +10:00
Mythie
3aea62e898 fix: styling and semantic updates 2023-06-21 23:48:22 +10:00
Lucas Smith
76674523c5 Merge pull request #208 from doug-andrade/refesh/document-loading
improved loading state for /document/id
2023-06-16 00:19:37 +10:00
Doug Andrade
e0e2f3e440 improved loading state for /document/id 2023-06-13 23:28:25 -04:00
Doug Andrade
d1bc948f3c clean up console.log() used for testing 2023-06-13 02:00:45 -04:00
Doug Andrade
2b84636993 feat: google auth without schema change 2023-06-13 01:53:12 -04:00
Lucas Smith
05238f096b feat: dark mode & theme switching
feat: dark mode & theme switching
2023-06-12 16:01:02 +10:00
Doug Andrade
dd83d4607c fix: dark mode on signup and signin pages 2023-06-11 12:26:47 -04:00
Doug Andrade
07d13c74f5 fix: signature pad in dark mode 2023-06-11 11:36:13 -04:00
Doug Andrade
64d1d6df37 resolving eslint build errors 2023-06-11 02:21:13 -04:00
Doug Andrade
877a579533 adding dark mode to feat/refresh 2023-06-11 01:50:19 -04:00
Mythie
b0e364acf4 wip: create document workflow 2023-06-10 22:33:12 +10:00
Mythie
803ebccee3 wip: refresh design 2023-06-09 18:22:21 +10:00
371 changed files with 6995 additions and 69820 deletions

View File

@@ -9,5 +9,10 @@ npm install
# Copy the env file # Copy the env file
cp .env.example .env cp .env.example .env
# Source the env file, export the variables
set -a
source .env
set +a
# Run the migrations # Run the migrations
npm run prisma:migrate-dev npm run -w @documenso/prisma prisma:migrate-dev

View File

@@ -15,11 +15,6 @@ NEXT_PRIVATE_DATABASE_URL="postgres://documenso:password@127.0.0.1:54320/documen
# Defines the URL to use for the database when running migrations and other commands that won't work with a connection pool. # Defines the URL to use for the database when running migrations and other commands that won't work with a connection pool.
NEXT_PRIVATE_DIRECT_DATABASE_URL="postgres://documenso:password@127.0.0.1:54320/documenso" NEXT_PRIVATE_DIRECT_DATABASE_URL="postgres://documenso:password@127.0.0.1:54320/documenso"
# [[E2E Tests]]
E2E_TEST_AUTHENTICATE_USERNAME="Test User"
E2E_TEST_AUTHENTICATE_USER_EMAIL="testuser@mail.com"
E2E_TEST_AUTHENTICATE_USER_PASSWORD="test_password"
# [[STORAGE]] # [[STORAGE]]
# OPTIONAL: Defines the storage transport to use. Available options: database (default) | s3 # OPTIONAL: Defines the storage transport to use. Available options: database (default) | s3
NEXT_PUBLIC_UPLOAD_TRANSPORT="database" NEXT_PUBLIC_UPLOAD_TRANSPORT="database"
@@ -73,7 +68,6 @@ NEXT_PRIVATE_STRIPE_API_KEY=
NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET= NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET=
NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID= NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID=
NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID= NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID=
NEXT_PUBLIC_STRIPE_FREE_PLAN_ID=
# [[FEATURES]] # [[FEATURES]]
# OPTIONAL: Leave blank to disable PostHog and feature flags. # OPTIONAL: Leave blank to disable PostHog and feature flags.

View File

@@ -1,48 +0,0 @@
name: "Bug Report"
labels: ["bug"]
description: Create a bug report to help us improve
body:
- type: markdown
attributes:
value:
Thank you for reporting an issue.
Please fill in as much of the form below as you're able to.
- type: textarea
attributes:
label: Issue Description
description: Please provide a clear and concise description of the problem.
- type: textarea
attributes:
label: Steps to Reproduce
description: Please provide step-by-step instructions to reproduce the issue. Include code snippets, error messages, and any other relevant information.
- type: textarea
attributes:
label: Expected Behavior
description: Describe what you expected to happen.
- type: textarea
attributes:
label: Current Behavior
description: Describe what is currently happening.
- type: textarea
attributes:
label: Screenshots (optional)
description: If applicable, add screenshots to help explain the issue.
- type: input
attributes:
label: Operating System [e.g., Windows 10]
- type: input
attributes:
label: Browser [e.g., Chrome, Firefox]
- type: input
attributes:
label: Version [e.g., 2.0.1]
- type: checkboxes
attributes:
label: Please check the boxes that apply to this issue report.
options:
- label: I have searched the existing issues to make sure this is not a duplicate.
- label: I have provided steps to reproduce the issue.
- label: I have included relevant environment information.
- label: I have included any relevant screenshots.
- label: I understand that this is a voluntary contribution and that there is no guarantee of resolution.
- label: I want to work on creating a PR for this issue if approved

View File

@@ -1,35 +0,0 @@
name: "Feature Request"
description: Suggest a new idea or enhancement for this project
body:
- type: markdown
attributes:
value: Please provide a clear and concise title for your feature request
- type: textarea
attributes:
label: Feature Description
description: Describe the feature you are requesting in detail. Explain what problem it solves or what value it adds to the project.
- type: textarea
attributes:
label: Use Case
description: 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.
- type: textarea
attributes:
label: Proposed Solution
description: 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.
- type: textarea
attributes:
label: Alternatives (optional)
description: Are there any alternative ways to achieve the same goal? Describe other approaches that could be considered if this feature is not implemented.
- type: textarea
attributes:
label: Additional Context
description: Add any additional context or information that might be relevant to the feature request.
- type: checkboxes
attributes:
label: Please check the boxes that apply to this feature request.
options:
- label: I have searched the existing feature requests to make sure this is not a duplicate.
- label: I have provided a detailed description of the requested feature.
- label: I have explained the use case or scenario for this feature.
- label: I have included any relevant technical details or design suggestions.
- label: I understand that this is a suggestion and that there is no guarantee of implementation.

View File

@@ -1,35 +0,0 @@
name: "General Improvement"
description: Suggest a minor enhancement or improvement for this project
body:
- type: markdown
attributes:
value: Please provide a clear and concise title for your improvement suggestion
- type: textarea
attributes:
label: Improvement Description
description: Describe the improvement you are suggesting in detail. Explain what specific aspect of the project it addresses or enhances.
- type: textarea
attributes:
label: Rationale
description: Explain why this improvement would be beneficial. Share any context, pain points, or reasons for suggesting this change.
- type: textarea
attributes:
label: Proposed Solution
description: 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.
- type: textarea
attributes:
label: Alternatives (optional)
description: Are there any alternative approaches to achieve the same improvement? Describe other ways to address the issue or enhance the project.
- type: textarea
attributes:
label: Additional Context
description: Add any additional context or information that might be relevant to the improvement suggestion.
- type: checkboxes
attributes:
label: Please check the boxes that apply to this improvement suggestion.
options:
- label: I have searched the existing issues and improvement suggestions to avoid duplication.
- label: I have provided a clear description of the improvement being suggested.
- label: I have explained the rationale behind this improvement.
- label: I have included any relevant technical details or design suggestions.
- label: I understand that this is a suggestion and that there is no guarantee of implementation.

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. -->

View File

@@ -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. -->

View File

@@ -5,28 +5,28 @@ updates:
directory: '/' directory: '/'
schedule: schedule:
interval: "weekly" interval: "weekly"
target-branch: "main" target-branch: "feat/refresh"
labels: labels:
- "ci dependencies" - "ci dependencies"
- "ci" - "ci"
open-pull-requests-limit: 0 open-pull-requests-limit: 2
- package-ecosystem: "npm" - package-ecosystem: "npm"
directory: "/apps/marketing" directory: "/apps/marketing"
schedule: schedule:
interval: "weekly" interval: "weekly"
target-branch: "main" target-branch: "feat/refresh"
labels: labels:
- "npm dependencies" - "npm dependencies"
- "frontend" - "frontend"
open-pull-requests-limit: 0 open-pull-requests-limit: 2
- package-ecosystem: "npm" - package-ecosystem: "npm"
directory: "/apps/web" directory: "/apps/web"
schedule: schedule:
interval: "weekly" interval: "weekly"
target-branch: "main" target-branch: "feat/refresh"
labels: labels:
- "npm dependencies" - "npm dependencies"
- "frontend" - "frontend"
open-pull-requests-limit: 0 open-pull-requests-limit: 2

View File

@@ -2,9 +2,9 @@ name: "Continuous Integration"
on: on:
push: push:
branches: [ "main" ] branches: [ "feat/refresh" ]
pull_request: pull_request:
branches: [ "main" ] branches: [ "feat/refresh" ]
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
@@ -14,8 +14,8 @@ env:
HUSKY: 0 HUSKY: 0
jobs: jobs:
build_app: build:
name: Build App name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
@@ -37,16 +37,3 @@ jobs:
- name: Build - name: Build
run: npm run build run: npm run build
build_docker:
name: Build Docker Image
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Build Docker Image
run: ./docker/build.sh

View File

@@ -3,9 +3,9 @@ name: "CodeQL"
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: [ "main" ] branches: [ feat/refresh ]
pull_request: pull_request:
branches: [ "main" ] branches: [ feat/refresh ]
jobs: jobs:
analyze: analyze:

View File

@@ -1,51 +0,0 @@
name: Playwright Tests
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
e2e_tests:
timeout-minutes: 60
runs-on: ubuntu-latest
services:
postgres:
image: postgres
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Copy env
run: cp .env.example .env
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Generate Prisma Client
run: npm run prisma:generate -w @documenso/prisma
- name: Create the database
run: npm run prisma:migrate-dev
- name: Run Playwright tests
run: npm run ci
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
env:
NEXT_PRIVATE_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/documenso
NEXT_PRIVATE_DIRECT_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/documenso
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}

1
.gitignore vendored
View File

@@ -31,7 +31,6 @@ yarn-error.log*
# turbo # turbo
.turbo .turbo
.turbo-cookie
# vercel # vercel
.vercel .vercel

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

View File

@@ -1,16 +0,0 @@
node_modules
.next
public
**/**/node_modules
**/**/.next
**/**/public
*.lock
*.log
*.test.ts
.gitignore
.npmignore
.prettierignore
.DS_Store
.eslintignore

View File

@@ -1,126 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of
any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address,
without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
support@documenso.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].

View File

@@ -5,39 +5,23 @@ If you plan to contribute to Documenso, please take a moment to feel awesome ✨
## Before getting started ## 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. - 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 - Select and issue from [here](https://github.com/documenso/documenso/issues) or create a new one
- Consider the results from the discussion on the issue - 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. - Accept the [Contributor License Agreement](https://documen.so/cla) to ensure we can accept your contributions.
## Taking issues
Before taking an issue, ensure that:
- The issue has been assigned the public label
- The issue is clearly defined and understood
- No one has been assigned to the issue
- No one has expressed intention to work on it
You can then:
1. Comment on the issue with your intention to work on it
2. Begin work on the issue
Always feel free to ask questions or seek clarification on the issue.
## Developing ## 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 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your
own GitHub account and then own GitHub account and then
[clone](https://help.github.com/articles/cloning-a-repository/) it to your local device. [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device.
2. Create a new branch: 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 ```sh
git checkout -b feat/doc-999-somefeature-that-rocks git checkout -b doc-999-my-feature-or-fix
``` ```
3. See the [Developer Setup](https://github.com/documenso/documenso/blob/main/README.md#developer-setup) for more setup details. 3. See the [Developer Setup](https://github.com/documenso/documenso/blob/main/README.md#developer-setup) for more setup details.
@@ -45,7 +29,7 @@ The development branch is <code>main</code>. All pull requests should be made ag
## Building ## Building
> **Note** > **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: You can build the project with:

View File

@@ -1,6 +0,0 @@
# The Documenso Manifest
Signing documents is a fundamental building block of private, economic, and government interactions. Access to easy and secure signing to participate in society should therefore be a fundamental right for everyone. The technology to enable this should be accessible and widespread.
We know that open source is the key to solving this need once and for all to benefit all humankind. Using open source kickstarts innovation by putting the open sharing of ideas and solutions first. With Documenso, we will create an open and globally accessible signing platform to empower users, customers, and developers to fulfill their needs. Documenso is built by and for the global community, listening and implementing what is needed. Being transparent with the code and the processes that use it brings trust and security to the platform.
We build Documenso for longevity and scale by embracing the capital efficiency and inclusiveness of the Commercial Open Source (COSS) movement. We are building a global commodity for the world.

348
README.md
View File

@@ -1,6 +1,8 @@
<img src="https://github.com/documenso/documenso/assets/13398220/a643571f-0239-46a6-a73e-6bef38d1228b" alt="Documenso Logo"> <p align="center" style="margin-top: 120px">
<a href="https://github.com/documenso/documenso">
<img width="250px" src="https://github.com/documenso/documenso/assets/1309312/ea8de2d0-8e33-4527-8a5c-40780142a2ed" alt="Documenso Logo">
</a>
<p align="center" style="margin-top: 20px">
<p align="center"> <p align="center">
The Open Source DocuSign Alternative. The Open Source DocuSign Alternative.
<br> <br>
@@ -14,8 +16,6 @@
<a href="https://github.com/documenso/documenso/issues">Issues</a> <a href="https://github.com/documenso/documenso/issues">Issues</a>
· ·
<a href="https://github.com/documenso/documenso/milestones">Roadmap</a> <a href="https://github.com/documenso/documenso/milestones">Roadmap</a>
·
<a href="https://documen.so/launches">Upcoming Launches</a>
</p> </p>
</p> </p>
@@ -24,12 +24,16 @@
<a href="https://github.com/documenso/documenso/stargazers"><img src="https://img.shields.io/github/stars/documenso/documenso" alt="Github Stars"></a> <a href="https://github.com/documenso/documenso/stargazers"><img src="https://img.shields.io/github/stars/documenso/documenso" alt="Github Stars"></a>
<a href="https://github.com/documenso/documenso/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPLv3-purple" alt="License"></a> <a href="https://github.com/documenso/documenso/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPLv3-purple" alt="License"></a>
<a href="https://github.com/documenso/documenso/pulse"><img src="https://img.shields.io/github/commit-activity/m/documenso/documenso" alt="Commits-per-month"></a> <a href="https://github.com/documenso/documenso/pulse"><img src="https://img.shields.io/github/commit-activity/m/documenso/documenso" alt="Commits-per-month"></a>
<a href="https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/documenso/documenso">
<img alt="open in devcontainer" src="https://img.shields.io/static/v1?label=Dev%20Containers&message=Enabled&color=blue&logo=visualstudiocode" />
</a>
<a href="code_of_conduct.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg" alt="Contributor Covenant"></a>
</p> </p>
> 🦺 Documenso 1.0 is deployed to our <a href="https://documen.so/staging" target="_blank">Staging Environment</a>.
>
> The code can be found on the [feat/refresh](https://github.com/documenso/documenso/tree/feat/refresh) branch.
>
> The new Version will be released after the current testing phase.
# Join us in testing Documenso 1.0 during [MALFUNCTION MANIA](https://documenso.com/blog/malfunction-mania)
<div> <div>
<img style="display: block; height: 120px; width: 24%" <img style="display: block; height: 120px; width: 24%"
src="https://github.com/documenso/documenso/assets/1309312/67e08c98-c153-4115-aa2d-77979bb12c94)"> src="https://github.com/documenso/documenso/assets/1309312/67e08c98-c153-4115-aa2d-77979bb12c94)">
@@ -45,31 +49,23 @@
## About this project ## About this project
Signing documents digitally should be fast and easy and should be the best practice for every document signed worldwide. Signing documents digitally is fast and easy and should be the best practice for every document signed worldwide. This is technically quite easy today, but it also introduces a new party to every signature: The signing tool providers. While this is not a problem in itself, it should make us think about how we want these providers of trust to work. Documenso aims to be the world's most trusted document-signing tool. This trust is built by empowering you to self-host Documenso and review how it works under the hood. Join us in creating the next generation of open trust infrastructure.
This is technically quite easy today, but it also introduces a new party to every signature: The signing tool providers. While this is not a problem in itself, it should make us think about how we want these providers of trust to work.
Documenso aims to be the world's most trusted document-signing tool. This trust is built by empowering you to self-host Documenso and review how it works under the hood.
Join us in creating the next generation of open trust infrastructure.
## Recognition ## Recognition
<p align="center"> <a href="https://www.producthunt.com/posts/documenso?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-documenso" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=395047&theme=light&period=daily" alt="Documenso - The&#0032;open&#0032;source&#0032;DocuSign&#0032;alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<a href="https://www.producthunt.com/posts/documenso?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-documenso" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=395047&theme=light&period=daily" alt="Documenso - The&#0032;open&#0032;source&#0032;DocuSign&#0032;alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a> <a href="https://www.producthunt.com/posts/documenso?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-documenso" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=395047&theme=light" alt="Documenso - The&#0032;Open&#0032;Source&#0032;DocuSign&#0032;Alternative&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<a href="https://www.producthunt.com/posts/documenso?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-documenso" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=395047&theme=light" alt="Documenso - The&#0032;Open&#0032;Source&#0032;DocuSign&#0032;Alternative&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</p>
## Community and Next Steps 🎯 ## Community and Next Steps 🎯
We're currently working on a redesign of the application, including a revamp of the codebase, so Documenso can be more intuitive to use and robust to develop upon. We're currently working on a redesign of the application, including a revamp of the codebase so Documenso can be more intuitive to use and robust to develop upon.
- Check out the first source code release in this repository and test it. - Check out the first source code release in this repository and test it
- Tell us what you think in the [Discussions](https://github.com/documenso/documenso/discussions). - Tell us what you think in the current [Discussions](https://github.com/documenso/documenso/discussions)
- Join the [Discord server](https://documen.so/discord) for any questions and getting to know to other community members. - Join the [Discord server](https://documen.so/discord) for any questions and getting to know to other community members
- ⭐ the repository to help us raise awareness. - ⭐ the repository to help us raise awareness
- Spread the word on Twitter that Documenso is working towards a more open signing tool. - Spread the word on Twitter that Documenso is working towards a more open signing tool
- Fix or create [issues](https://github.com/documenso/documenso/issues), that are needed for the first production release. - Fix or create [issues](https://github.com/documenso/documenso/issues), that are needed for the first production release
## Contributing ## Contributing
@@ -81,107 +77,96 @@ Contact us if you are interested in our Enterprise plan for large organizations
<a href="https://cal.com/timurercan/enterprise-customers?utm_source=banner&utm_campaign=oss"><img alt="Book us with Cal.com" src="https://cal.com/book-with-cal-dark.svg" /></a> <a href="https://cal.com/timurercan/enterprise-customers?utm_source=banner&utm_campaign=oss"><img alt="Book us with Cal.com" src="https://cal.com/book-with-cal-dark.svg" /></a>
## Tech Stack ## Activity
- [Typescript](https://www.typescriptlang.org/) - Language ![Repository Activity](https://repobeats.axiom.co/api/embed/622a2e9aa709696f7226304b5b7178a5741b3868.svg)
- [Next.js](https://nextjs.org/) - Framework
- [Prisma](https://www.prisma.io/) - ORM
- [Tailwind](https://tailwindcss.com/) - CSS
- [shadcn/ui](https://ui.shadcn.com/) - Component Library
- [NextAuth.js](https://next-auth.js.org/) - Authentication
- [react-email](https://react.email/) - Email Templates
- [tRPC](https://trpc.io/) - API
- [Node SignPDF](https://github.com/vbuch/node-signpdf) - Digital Signature
- [React-PDF](https://github.com/wojtekmaj/react-pdf) - Viewing PDFs
- [PDF-Lib](https://github.com/Hopding/pdf-lib) - PDF manipulation
- [Stripe](https://stripe.com/) - Payments
- [Vercel](https://vercel.com) - Hosting
<!-- - Support for [opensignpdf (requires Java on server)](https://github.com/open-pdf-sign) is currently planned. --> # Tech
## Local Development Documenso is built using awesome open source tech including:
### Requirements - [Typescript](https://www.typescriptlang.org/)
- [Javascript (when necessary)](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
- [NextJS (JS Fullstack Framework)](https://nextjs.org/)
- [Postgres SQL (Database)](https://www.postgresql.org/)
- [Prisma (ORM - Object-relational mapping)](https://www.prisma.io/)
- [Tailwind CSS (Styling)](https://tailwindcss.com/)
- [Node SignPDF (Digital Signature)](https://github.com/vbuch/node-signpdf)
- [React-PDF for viewing PDFs](https://github.com/wojtekmaj/react-pdf)
- [PDF-Lib for PDF manipulation](https://github.com/Hopding/pdf-lib)
- Check out `/package.json` and `/apps/web/package.json` for more
- Support for [opensignpdf (requires Java on server)](https://github.com/open-pdf-sign) is currently planned.
To run Documenso locally, you will need # Getting Started
- Node.js ## Requirements
- Postgres SQL Database
- Docker (optional)
### Developer Quickstart To run Documenso locally you need
- [Node.js (Version: >=18.x)](https://nodejs.org/en/download/)
- Node Package Manager NPM - included in Node.js
- [PostgreSQL (local or remote)](https://www.postgresql.org/download/)
## Developer Quickstart
> **Note**: This is a quickstart for developers. It assumes that you have both [docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/) installed on your machine. > **Note**: This is a quickstart for developers. It assumes that you have both [docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/) installed on your machine.
Want to get up and running quickly? Follow these steps: Want to get up and running quickly? Follow these steps:
1. [Clone the repository](https://help.github.com/articles/cloning-a-repository/) it to your local device. - [Clone the repository](https://help.github.com/articles/cloning-a-repository/) it to your local device.
```sh ```sh
git clone https://github.com/documenso/documenso git clone https://github.com/documenso/documenso
``` ```
2. Set up your `.env` file using the recommendations in the `.env.example` file. Alternatively, just run `cp .env.example .env` to get started with our handpicked defaults. - Set up your `.env` file using the recommendations in the `.env.example` file.
- Run `npm run dx` in the root directory
- This will spin up a postgres database and inbucket mail server in docker containers.
- Run `npm run dev` in the root directory
- Want it even faster? Just use
```sh
npm run d
```
3. Run `npm run dx` in the root directory That's it! You should now be able to access the app at http://localhost:3000
- This will spin up a postgres database and inbucket mailserver in a docker container. Incoming mail will be available at http://localhost:9000
4. Run `npm run dev` in the root directory Your database will also be available on port `54320`. You can connect to it using your favorite database client.
5. Want it even faster? Just use
```sh
npm run d
```
#### Access Points for Your Application
1. **App** - http://localhost:3000
2. **Incoming Mail Access** - http://localhost:9000
3. **Database Connection Details**
- **Port**: 54320
- **Connection**: Use your favorite database client to connect using the provided port.
## Developer Setup ## Developer Setup
### Manual Setup ### Manual Setup
Follow these steps to setup Documenso on your local machine: Follow these steps to setup documenso on you local machine:
1. [Clone the repository](https://help.github.com/articles/cloning-a-repository/) it to your local device. - [Clone the repository](https://help.github.com/articles/cloning-a-repository/) it to your local device.
```sh
```sh git clone https://github.com/documenso/documenso
git clone https://github.com/documenso/documenso ```
``` - Run `npm i` in root directory
- Rename `.env.example` to `.env`
2. Run `npm i` in the root directory - Set DATABASE_URL value in .env file
- You can use the provided test database url (may be wiped at any point)
3. Create your `.env` from the `.env.example`. You can use `cp .env.example .env` to get started with our handpicked defaults. - Or setup a local postgres sql instance (recommended)
- Create the database scheme by running `db-migrate:dev`
4. Set the following environment variables: - Setup your mail provider
- Set `SENDGRID_API_KEY` value in .env file
- NEXTAUTH_URL - You need a SendGrid account, which you can create [here](https://signup.sendgrid.com/).
- NEXTAUTH_SECRET - Documenso uses [Nodemailer](https://nodemailer.com/about/) so you can easily use your own SMTP server by setting the `SMTP
- NEXT_PUBLIC_WEBAPP_URL \_
- NEXT_PUBLIC_MARKETING_URL * variables` in your .env
- NEXT_PRIVATE_DATABASE_URL - Run `npm run dev` root directory to start
- NEXT_PRIVATE_DIRECT_DATABASE_URL - Register a new user at http://localhost:3000/signup
- NEXT_PRIVATE_SMTP_FROM_NAME
- NEXT_PRIVATE_SMTP_FROM_ADDRESS
5. Create the database schema by running `npm run prisma:migrate-dev`
6. Run `npm run dev` in the root directory to start
7. Register a new user at http://localhost:3000/signup
--- ---
- Optional: Seed the database using `npm run prisma:seed -w @documenso/prisma` to create a test user and document. - Optional: Seed the database using `npm run db-seed` to create a test user and document
- Optional: Create your own signing certificate. - Optional: Upload and sign `apps/web/resources/example.pdf` manually to test your setup
- To generate your own using these steps and a Linux Terminal or Windows Subsystem for Linux (WSL), see **[Create your own signing certificate](./SIGNING.md)**.
- Optional: Create your own signing certificate
- A demo certificate is provided in `/app/web/resources/certificate.p12`
- To generate your own using these steps and a Linux Terminal or Windows Subsystem for Linux (WSL) see **[Create your own signing certificate](#creating-your-own-signing-certificate)**.
### Run in Gitpod ### Run in Gitpod
@@ -189,112 +174,81 @@ git clone https://github.com/documenso/documenso
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/documenso/documenso) [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/documenso/documenso)
### Run in DevContainer ## Updating
We support DevContainers for VSCode. [Click here to get started.](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/documenso/documenso) - If you pull the newest version from main, using `git pull`, it may be necessary to regenerate your database client
- You can do this by running the generate command in `/packages/prisma`:
```sh
npx prisma generate
```
- This is not necessary on first clone.
### Video walkthrough # Creating your own signing certificate
If you're a visual learner and prefer to watch a video walkthrough of setting up Documenso locally, check out this video: For the digital signature of your documents you need a signing certificate in .p12 format (public and private key). You can buy one (not recommended for dev) or use the steps to create a self-signed one:
[![Watch the video](https://img.youtube.com/vi/Y0ppIQrEnZs/hqdefault.jpg)](https://youtu.be/Y0ppIQrEnZs) 1. Generate a private key using the OpenSSL command. You can run the following command to generate a 2048-bit RSA key:
## Docker `openssl genrsa -out private.key 2048`
🚧 Docker containers and images are current in progress. We are actively working on bringing a simple Docker build and publish pipeline for Documenso. 2. Generate a self-signed certificate using the private key. You can run the following command to generate a self-signed certificate:
## Self Hosting `openssl req -new -x509 -key private.key -out certificate.crt -days 365`
This will prompt you to enter some information, such as the Common Name (CN) for the certificate. Make sure you enter the correct information. The -days parameter sets the number of days for which the certificate is valid.
3. Combine the private key and the self-signed certificate to create the p12 certificate. You can run the following command to do this:
`openssl pkcs12 -export -out certificate.p12 -inkey private.key -in certificate.crt`
4. You will be prompted to enter a password for the p12 file. Choose a strong password and remember it, as you will need it to use the certificate (**can be empty for dev certificates**)
5. Place the certificate `/apps/web/resources/certificate.p12`
# Docker
> We are still working on the publishing of docker images, in the meantime you can follow the steps below to create a production ready docker image.
Want to create a production ready docker image? Follow these steps:
- cd into `docker` directory
- Make `build.sh` executable by running `chmod +x build.sh`
- Run `./build.sh` to start building the docker image.
- Publish the image to your docker registry of choice (or) If you prefer running the image from local, run the below command
```
docker run -d --restart=unless-stopped -p 3000:3000 -v documenso:/app/data --name documenso documenso:latest
```
Command Breakdown:
- `-d` - Let's you run the container in background
- `-p` - Passes down which ports to use. First half is the host port, Second half is the app port. You can change the first half anything you want and reverse proxy to that port.
- `-v` - Volume let's you persist the data
- `--name` - Name of the container
- `documenso:latest` - Image you have built
# Deployment
We support a variety of deployment methods, and are actively working on adding more. Stay tuned for updates! We support a variety of deployment methods, and are actively working on adding more. Stay tuned for updates!
> Please note that the below deployment methods are for v0.9, we will update these to v1.0 once it has been released. ## Railway
### Fetch, configure, and build
First, clone the code from Github:
```
git clone https://github.com/documenso/documenso.git
```
Then, inside the `documenso` folder, copy the example env file:
```
cp .env.example .env
```
The following environment variables must be set:
* `NEXTAUTH_URL`
* `NEXTAUTH_SECRET`
* `NEXT_PUBLIC_WEBAPP_URL`
* `NEXT_PUBLIC_MARKETING_URL`
* `NEXT_PRIVATE_DATABASE_URL`
* `NEXT_PRIVATE_DIRECT_DATABASE_URL`
* `NEXT_PRIVATE_SMTP_FROM_NAME`
* `NEXT_PRIVATE_SMTP_FROM_ADDRESS`
> If you are using a reverse proxy in front of Documenso, don't forget to provide the public URL for both `NEXTAUTH_URL` and `NEXT_PUBLIC_WEBAPP_URL` variables!
Now you can install the dependencies and build it:
```
npm i
npm run:build:web
npm run prisma:migrate-deploy
```
Finally, you can start it with:
```
npm run start
```
This will start the server on `localhost:3000`. For now, any reverse proxy can then do the frontend and SSL termination.
> If you want to run with another port than 3000, you can start the application with `next -p <ANY PORT>` from the `apps/web` folder.
### Run as a service
You can use a systemd service file to run the app. Here is a simple example of the service running on port 3500 (using 3000 by default):
```bash
[Unit]
Description=documenso
After=network.target
[Service]
Environment=PATH=/path/to/your/node/binaries
Type=simple
User=www-data
WorkingDirectory=/var/www/documenso/apps/web
ExecStart=/usr/bin/next start -p 3500
TimeoutSec=15
Restart=always
[Install]
WantedBy=multi-user.target
```
### Railway
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/DjrRRX) [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/DjrRRX)
### Render ## Render
[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/documenso/documenso) [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/documenso/documenso)
## Troubleshooting # Troubleshooting
### I'm not receiving any emails when using the developer quickstart. ## I'm not receiving any emails when using the developer quickstart
When using the developer quickstart, an [Inbucket](https://inbucket.org/) server will be spun up in a docker container that will store all outgoing emails locally for you to view. When using the developer quickstart an [Inbucket](https://inbucket.org/) server will be spun up in a docker container that will store all outgoing email locally for you to view.
The Web UI can be found at http://localhost:9000, while the SMTP port will be on localhost:2500. The Web UI can be found at http://localhost:9000 while the SMTP port will be on localhost:2500.
### Support IPv6 ## Support IPv6
If you are deploying to a cluster that uses only IPv6, You can use a custom command to pass a parameter to the Next.js start command In case you are deploying to a cluster that uses only IPv6. You can use a custom command to pass a parameter to the NextJS start command
For local docker run For local docker run
@@ -316,25 +270,5 @@ containers:
- start - start
- -- - --
- -H - -H
- '::' - "::"
``` ```
### 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 the 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)

View File

@@ -1,55 +0,0 @@
# Creating your own signing certificate
For the digital signature of your documents you need a signing certificate in .p12 format (public and private key). You can buy one (not recommended for dev) or use the steps to create a self-signed one:
1. Generate a private key using the OpenSSL command. You can run the following command to generate a 2048-bit RSA key:
`openssl genrsa -out private.key 2048`
2. Generate a self-signed certificate using the private key. You can run the following command to generate a self-signed certificate:
`openssl req -new -x509 -key private.key -out certificate.crt -days 365`
This will prompt you to enter some information, such as the Common Name (CN) for the certificate. Make sure you enter the correct information. The -days parameter sets the number of days for which the certificate is valid.
3. Combine the private key and the self-signed certificate to create the p12 certificate. You can run the following command to do this:
`openssl pkcs12 -export -out certificate.p12 -inkey private.key -in certificate.crt`
4. You will be prompted to enter a password for the p12 file. Choose a strong password and remember it, as you will need it to use the certificate (**can be empty for dev certificates**)
5. Place the certificate `/apps/web/resources/certificate.p12`
## Docker
> We are still working on the publishing of docker images, in the meantime you can follow the steps below to create a production ready docker image.
Want to create a production ready docker image? Follow these steps:
- cd into `docker` directory
- Make `build.sh` executable by running `chmod +x build.sh`
- Run `./build.sh` to start building the docker image.
- Publish the image to your docker registry of choice (or) If you prefer running the image from local, run the below command
```
docker run -d --restart=unless-stopped -p 3000:3000 -v documenso:/app/data --name documenso documenso:latest
```
Command Breakdown:
- `-d` - Let's you run the container in background
- `-p` - Passes down which ports to use. First half is the host port, Second half is the app port. You can change the first half anything you want and reverse proxy to that port.
- `-v` - Volume let's you persist the data
- `--name` - Name of the container
- `documenso:latest` - Image you have built
## Deployment
We support a variety of deployment methods, and are actively working on adding more. Stay tuned for updates!
## Railway
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/DjrRRX)
## Render
[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/documenso/documenso)

View File

@@ -1,6 +1,6 @@
--- ---
title: 'Building Documenso — Part 1: Certificates' title: 'Building Documenso — Part 1: Certificates'
description: In today's fast-paced world, productivity and efficiency are crucial for success, both in personal and professional endeavors. We all strive to make the most of our time and energy to achieve our goals effectively. However, it's not always easy to stay on track and maintain peak performance. In this blog post, we'll explore 10 valuable tips to help you boost productivity and efficiency in your daily life. description: This is the first part of the new Building Documenso series, where I describe the challenges and design choices that we make while building the worlds most open signing platform.
authorName: 'Timur Ercan' authorName: 'Timur Ercan'
authorImage: '/blog/blog-author-timur.jpeg' authorImage: '/blog/blog-author-timur.jpeg'
authorRole: 'Co-Founder' authorRole: 'Co-Founder'

View File

@@ -1,49 +0,0 @@
---
title: Open Sourcing Documenso's Design
description: It's day 1 of our first launch week. We are kicking it off by open sourcing Documenso's design system! Let's go..
authorName: 'Timur Ercan'
authorImage: '/blog/blog-author-timur.jpeg'
authorRole: 'Co-Founder'
date: 2023-09-25
tags:
- Design
- Open Source
- Community
---
<figure>
<MdxNextImage
src="/blog/designsystem.png"
width="1260"
height="630"
alt="Documenso's Design System"
/>
<figcaption className="text-center">
Documenso's Design System ✨
</figcaption>
</figure>
> TLDR; Our design system is OSS under MIT at [design.documenso.com](https://design.documenso.com)
Today, we are open sourcing our design system, lovingly crafted by [Thilo](https://twitter.com/thilokonzok). The system is public on Figma and will be available at [design.documenso.com](https://design.documenso.com) from here on out.
We are publishing it under the MIT License so everyone can share, remix, and use it as it helps them most.
We chose to start our first launch week with a design topic to emphasize the role design will play in Documenso's company and community culture. As it is historically difficult to bring together open-source software with great design, this is our first step towards encouraging a more design-driven COSS (Commercial Open Source) movement.
## Designers Welcome
We added a designer role in our Discord to create a space for designers to explore and discuss design-related topics of Documenso and signing in general. In the future, we want to foster more coding contributions and start a design culture around the product. As it is much more difficult to incorporate design contributions, we have yet to find a clear plan of what that will look like. I would like to see contributions around stuff we are NOT working on. Designs in that area can inspire and start discussions without the complexities of implementing them immediately — a free-thinking space around everything Documenso. Having a free mandate to design without restriction can create many exciting ideas. Some Ideas worth exploring:
## Areas for design contributions
- Explorations of exciting aspects of signing and document handling:
- What does signing look like when we no longer have skeuomorphic signatures?
- What is signing if we move beyond paper-inspired documents?
- What would the government process look like using Documenso?
- Solutions Concepts for features further down the roadmap, e.g., Widgets in websites
These are fascinating ideas for explorative design. They won't be built 1:1 but shape how we think about signing and where it can go, which is even more critical. If you are interested in product design, you are invited to join our [Discord](https://documen.so/discord) and discuss the future of signing design or the future of Documenso's design system. Also let me know what you think on [X (formerly Twitter)](https://x.com/eltimuro).
Best from Hamburg\
Timur

View File

@@ -1,65 +0,0 @@
---
title: The Early Adopters Plan
description: Launch Week Day 4 and we are still early! Early enough for you to get a sweet deal for supporting Documenso's Mission. Join the movement and get a shiny early adopter account in the process.
authorName: 'Timur Ercan'
authorImage: '/blog/blog-author-timur.jpeg'
authorRole: 'Co-Founder'
date: 2023-09-28
tags:
- Paid Plan
- Metrics
- Open Startup
---
<figure>
<MdxNextImage
src="/blog/early.png"
width="1260"
height="630"
alt="XKCD: Bug"
/>
<figcaption className="text-center">
"Being early is, uh, good." -Unknown
</figcaption>
</figure>
## Community-Driven Development
As we ramp up hiring and development speed for Documenso, I want to discuss how we plan to build its core version.
As we want to be a highly community-driven product, we want to capture the thoughts and ideas of said community in two ways:
1. Everything we plan (i.e. documen.so/roadmap) and build (i.e. documen.so/repo) is public and open to comments and suggestions from everyone by design. We plan to have discussions, streams, and articles showcasing what we're up to, encouraging feedback and iterations on our plans.
2. We're looking for 100 die-hard early adopters to get more deep hands-on feedback. If you want to be among the first to use and help shape Documenso, we have a special offer for you:
## The Early Adopter Plan
- All first 100 signups are entitled to the early adopter plan.
- The plan includes everything we build in the next 12 months and unlimited<sup>1</sup> signatures
- This plan is priced at $30/mo.
- No matter what we add, the price is guaranteed for life as a thank you for supporting Documenso's mission<sup>2</sup>. And we plan to add a lot.
- This also includes unlimited users<sup>3</sup> as part of the upcoming support for teams.
- If you already claimed an early adopter account in the past and canceled, we are happy to reactivate your account with the early adopter pricing. Reach out to support@documenso.com
## Being an Early Adopter
Being eligible for the early adopter plan has no formal requirements like giving feedback or being active in the community. In good faith, we assume you sign the Documenso Supporter Pledge to be part of this. And if you want to use the newest version quietly, that's fine, too. Everything the die-hard community brings up will be carefully considered and prioritized <sup>4</sup>. Also, there will obviously be limited edition merch available for the first 100.
Documenso currently runs the community reviewed 0.9.1 version. Getting from here to the globally loved and adopted signing tool we all deserve will take a lot of work, and we want you on board to help us create it. Join us in shaping the future of open signing and having fun doing it. [Malfunction Mania](https://documenso.com/blog/malfunction-mania) and releasing 1.0 will go a long way.
## Extending our open metrics
As part of our ongoing effort to be open and transparent in our doing, we are adding "Early Adopters" to our [/open page](https://documenso.com/open) page. After we exceed the early adopter slots, this metric will transition to "Customers". When no more early adopter seats can be claimed, the early adopter plan will transition to a standard paid plan. It will still be priced at $30/mo., but will no longer include upcoming features or unlimited seats.
If you have any questions or comments, please reach out on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord).
Best from Hamburg\
Timur
\
[1] Excluding signatures, we have to pay for i.e. third-party QES
[2] The Documenso Manifest
[3] Within reason. If you are unsure what that means, feel free to contact hi@documenso.com. But it should be fine if you don't plan to onboard a huge enterprise.
[4] We won't be able to build everything everyone asks for. But we firmly plan to listen and build in a way everyone's requirements are met as well as possible.

View File

@@ -1,75 +0,0 @@
---
title: The 🔴 LIVE Roadmap
description: It's the Launch Week Day finale, Day 5! We are going out with a bang and introducing the 🔴 LIVE roadmap, featuring our next Product Hunt Launch - Free Singleplayer Documenso - Sign without creating an account!
authorName: 'Timur Ercan'
authorImage: '/blog/blog-author-timur.jpeg'
authorRole: 'Co-Founder'
date: 2023-09-29
tags:
- Free Plan
- Launch
- Roadmap
---
<figure>
<MdxNextImage
src="/blog/roadmap.png"
width="1260"
height="630"
alt="XKCD: Bug"
/>
<figcaption className="text-center">
"Being early is, uh, good." -Unknown
</figcaption>
</figure>
> TLDR; We are launching a [🔴 LIVE roadmap](https://documen.so/launches), that gets updated regularly.\
> First upcoming launch: A free single signer experience.
## The Road Ahead
It's been quite a week, launching our [design system](https://documenso.com/blog/design-system), [kicking of a Malfunction Mania](https://documenso.com/blog/malfunction-mania), a [shiny new contributor perk](https://documenso.com/blog/shop) and our [early adopter deal](https://documenso.com/blog/early-adopters). After discussing Version 1.0 a lot, we want to close the week by looking ahead. As an open company, we want transparency about what we are working on and what to expect next. Especially for our Early Adopters, we want to paint a clear picture of what to expect in the near term.
Communicating software development progress and goals is historically tricky because of it's complex nature. Exact release dates are notoriously unreliable; if they are not, they force a particular style of development, forcing the team to make tradeoffs on scope and quality.
To give an appropriate insight into our work, we are launching our new [🔴 LIVE roadmap](https://documen.so/launches) today:
- A List of quarterly development and feature goals
- That gets updated regularly (bi-weekly)
- Has up-to-date insights from the team on where we stand
**While there are some great features planned, one stands out: Single Player Mode!**
## Announcing Documenso Singleplayer Mode
<a href="https://www.producthunt.com/products/documenso" target="_blank">
<figure>
<MdxNextImage
src="/blog/sp5.png"
width="1260"
height="630"
/>
<figcaption className="text-center font-bold">
🚨 We are going back to Product Hunt! Are you ready, player one?
</figcaption>
</figure>
</a>
Single Player Mode will be a free, loginless signing experience for single signers. If you hate creating an account to sign a single, once-in-a-while-document yourself as much as we do, we've got you. Our new free tier will accompany Singleplayer. While you don't HAVE to create an account to sign sth. quickly, you can. A free tier Documenso Account will give you the following:
- A place to store all your sent and received Documenso-signed documents
- Free forever
- Unlimited recipients
- 5 free signatures per month (for now, excluding third party types like QES)
- The use of templates, as soon as we [release](https://documen.so/launches) them
Singleplayer will launch in the first half of October, shortly after the release of 1.0, **[ON PRODUCT HUNT!](https://www.producthunt.com/products/documenso)** That's right, we are going back to Product Hunt to kick of this new phase of Documenso and you are invited to join us once again :)
**[Subscribe on PH](https://www.producthunt.com/products/documenso)** to be notified when we launch.
If you have any questions or comments, please reach out on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord).
Best from Hamburg\
Timur

View File

@@ -16,7 +16,7 @@ tags:
src="/blog/mm.png" src="/blog/mm.png"
width="1260" width="1260"
height="630" height="630"
alt="Malfunctioning Documenso Logo in broken colors" alt="Malfunctioning Documenso Logo inbroken colors"
/> />
<figcaption className="text-center"> <figcaption className="text-center">
@@ -49,9 +49,9 @@ As Documenso 1.0 just hit the staging environment, we're calling a MALFUNCTION M
- Fix bugs by creating a Pull Request (PR); - Fix bugs by creating a Pull Request (PR);
- Look over and add missing documentation/ Quickstarts and other useful resources. - Look over and add missing documentation/ Quickstarts and other useful resources.
We don't have a specific end date for Malfunction Mania. We plan to move the staging version into the production environment by the end of the month once we're happy with the results. Bug reports and fixes are, of course, always welcome going forward.
Best from Hamburg Best from Hamburg
Timur Timur
We don't have a specific end date for Malfunction Mania. We plan to move the staging version into the production environment by the end of the month once we're happy with the results. Bug reports and fixes are, of course, always welcome going forward.
**[Follow Documenso on Twitter / X](https://documen.so/tw) and [join the Discord server](https://documen.so/discord) to get the latest about Malfunction Mania.** **[Follow Documenso on Twitter / X](https://documen.so/tw) and [join the Discord server](https://documen.so/discord) to get the latest about Malfunction Mania.**

View File

@@ -12,7 +12,7 @@ tags:
Since we launched [Documenso 0.9 on Product Hunt](https://producthunt.com/products/documenso#documenso) last May, the team's been hard at work behind the scenes to ramp up development and design to deliver an excellent next version. Since we launched [Documenso 0.9 on Product Hunt](https://producthunt.com/products/documenso#documenso) last May, the team's been hard at work behind the scenes to ramp up development and design to deliver an excellent next version.
Last week, Lucas shared the reasoning how [why we're doing a rewrite](https://documenso.com/blog/why-were-doing-a-rewrite). Last week, Lucas shared the reasoning on [why we're doing a rewrite](https://documenso.com/blog/why-were-doing-a-rewrite).
Today, I'm pleased to share with you a preview of the next Documenso. Today, I'm pleased to share with you a preview of the next Documenso.

View File

@@ -14,11 +14,9 @@ tags:
Today I'm happy to announce that we closed a \$1.25M Pre-Seed round for Documenso, bringing our total funding to \$1.54M. The round actually closed last month, we just were sneaky about it. Today I'm happy to announce that we closed a \$1.25M Pre-Seed round for Documenso, bringing our total funding to \$1.54M. The round actually closed last month, we just were sneaky about it.
## Two more for the road (to open signing) ## Two more for the road (to open signing)
We're ecstatic to welcome [OSS Capital](https://twitter.com/osscapital) and especially [Joseph Jacks](https://twitter.com/JosephJacks_) to the inner circle of the open signing revolution. We're also fortunate to be joined by Orrick's very own [John Harrison](https://www.linkedin.com/in/john-harrison-a1213b9/) and his legal experience. For those who are wondering, yes, the round was, of course, signed using Documenso. We're ecstatic to welcome [OSS Capital](https://twitter.com/osscapital) and especially [Joseph Jacks](https://twitter.com/JosephJacks_) to the inner circle of the open signing revolution. We're also fortunate to be joined by Orrick's very own [John Harrison](https://www.linkedin.com/in/john-harrison-a1213b9/) and his legal experience. For those who are wondering, yes, the round was, of course, signed using Documenso.
## Open Source, Open Metrics ## Open Source, Open Metrics
If you follow us, you know we're firmly committed to the open source values of openness and transparency. For us, this includes not only the code side of things but also the business. As we aim to build trust among our investors, customers, and partners, we want to be open about what's going on. We also want to allow everyone to learn from our data and choices, just as we did from so many other COSS (Commercial Open Source) startups. The term "Open Startup" isn't precisely defined (and probably will never be, just like startup). There is however a [great write-up](https://cal.com/blog/open-startup) about the basics by the founder of our favorite open source scheduling tool Cal.com. If you follow us, you know we're firmly committed to the open source values of openness and transparency. For us, this includes not only the code side of things but also the business. As we aim to build trust among our investors, customers, and partners, we want to be open about what's going on. We also want to allow everyone to learn from our data and choices, just as we did from so many other COSS (Commercial Open Source) startups. The term "Open Startup" isn't precisely defined (and probably will never be, just like startup). There is however a [great write-up](https://cal.com/blog/open-startup) about the basics by the founder of our favorite open source scheduling tool Cal.com.
The two main takeaways are: The two main takeaways are:

View File

@@ -24,9 +24,9 @@ Were an open-source project and focus on building a great developer experienc
So, were switching all conversations, team and community-wide, to Discord. So, were switching all conversations, team and community-wide, to Discord.
In this post, we wont debate _why_ were switching — Slack vs. Discord is a long-lasting debate with pros and cons, and fans on both sides. There are great [stories](https://blog.meilisearch.com/from-slack-to-discord-our-migration/) and [threads](https://twitter.com/McPizza0/status/1655519558600470528) on the topic. We just dont want to write yet another story here. In this post, we wont debate *why* were switching — Slack vs. Discord is a long-lasting debate with pros and cons, and fans on both sides. There are great [stories](https://blog.meilisearch.com/from-slack-to-discord-our-migration/) and [threads](https://twitter.com/McPizza0/status/1655519558600470528) on the topic. We just dont want to write yet another story here.
Instead, well focus on _how_ we plan to make the switch. Instead, well focus on *how* we plan to make the switch.
## Who is this story for? ## Who is this story for?
@@ -47,13 +47,14 @@ The detailed plan goes like this:
- 2023-08-02 `t+8`: We announce to the community the upcoming changes in the different channels — GitHub, Twitter, and Slack. - 2023-08-02 `t+8`: We announce to the community the upcoming changes in the different channels — GitHub, Twitter, and Slack.
- **GitHub** - **GitHub**
- Create new Pull Request - Create new Pull Request
- Add story to the blog - Add story to the blog
- Update link to the community - Update link to the community
``` ```
https://documen.so/discord https://documen.so/discord
``` ```
- Start a new Discussion - Start a new Discussion
```markdown ```markdown
@@ -72,7 +73,6 @@ The detailed plan goes like this:
``` ```
- **Twitter** - **Twitter**
- [Tweet the announcement](https://twitter.com/documenso/status/1686719482096766977) - [Tweet the announcement](https://twitter.com/documenso/status/1686719482096766977)
- Pin Tweet - Pin Tweet
- Update link in bio - Update link in bio
@@ -87,7 +87,6 @@ The detailed plan goes like this:
``` ```
- **Slack** - **Slack**
- Post message in `#general` - Post message in `#general`
```markdown ```markdown
@@ -107,15 +106,15 @@ The detailed plan goes like this:
- Pin post - Pin post
- Set topic and description - Set topic and description
``` ```
We're switching to Discord. Join the fun: https://documen.so/discord We're switching to Discord. Join the fun: https://documen.so/discord
``` ```
- Archive channels: `#code-review` `#how-to` `#meet-and-greet` `#random-memes` `#self-hosting` `#support` - Archive channels: `#code-review` `#how-to` `#meet-and-greet` `#random-memes` `#self-hosting` `#support`
- 2023-08-09 `t+15`: 7 days later, we send a reminder on Slack. - 2023-08-09 `t+15`: 7 days later, we send a reminder on Slack.
- **Slack** - **Slack**
- Schedule reminder in `#general` - Schedule reminder in `#general`
``` ```
@@ -132,5 +131,5 @@ The detailed plan goes like this:
## Final thoughts ## Final thoughts
- Were at the very, early stage on our journey to building a beautiful, open-source DocuSign alternative. We want to build a great developer experience with the open-source community and, switching to Discord, we want to set up the foundations of an open, safe place for community members to get in touch, brainstorm ideas, and have fun. - Were at the very, early stage on our journey to building a beautiful, open-source DocuSign alternative. We want to build a great developer experience with the open-source community and, switching to Discord, we want to set up the foundations of an open, safe place for community members to get in touch, brainstorm ideas, and have fun.
- It doesnt mean we wont ever switch back to Slack. The tools of today arent the ones of tomorrow. We dont delete the Slack workspace, we archive it, and keep the `documenso` handle. May it be just an _au revoir?_ - It doesnt mean we wont ever switch back to Slack. The tools of today arent the ones of tomorrow. We dont delete the Slack workspace, we archive it, and keep the `documenso` handle. May it be just an *au revoir?*
- For now, were pushing forward and are eager to welcome you on Discord. Make sure to [join the server](https://documen.so/discord) in order to keep up to date on all things Documenso. See you there! - For now, were pushing forward and are eager to welcome you on Discord. Make sure to [join the server](https://documen.so/discord) in order to keep up to date on all things Documenso. See you there!

View File

@@ -1,42 +0,0 @@
---
title: Design System
---
# We're building a beautiful, open-source alternative to DocuSign
> Read more about our design culture here:
>
> [https://documenso.com/blog/design-system](https://documenso.com/blog/design-system)
At Documenso, we aim to be a design-driven company.
We believe that design isn't just about how things look, but also how they work. We want to make sure that the product is easy to use and intuitive. We also want to ensure that the website, desktop and mobile apps are consistent and look and feel like they belong together.
To achieve this, we've created Documenso's design system containing tokens, primitives, and components, screens, and brand assets.
We're open-sourcing this design system so you can see how we build the product and think about design as a whole.
## Check out the design system
<iframe
src="https://documen.so/design-system-embed"
className="aspect-square w-full border-none"
frameBorder="0"
/>
## Remix and Share the community version on Figma
<a href="https://documen.so/design" target="_blank">
<figure>
<MdxNextImage
src="/blog/designsystem.png"
width="1260"
height="630"
alt="Documenso's Design System"
/>
<figcaption className="text-center">
Documenso's Design System ✨
</figcaption>
</figure>
</a>

View File

@@ -0,0 +1,69 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const { withContentlayer } = require('next-contentlayer');
require('dotenv').config({
path: path.join(__dirname, '../../.env.local'),
});
/** @type {import('next').NextConfig} */
const config = {
experimental: {
serverActions: true,
serverActionsBodySizeLimit: '10mb',
},
reactStrictMode: true,
transpilePackages: ['@documenso/lib', '@documenso/prisma', '@documenso/trpc', '@documenso/ui'],
env: {
NEXT_PUBLIC_PROJECT: 'marketing',
},
modularizeImports: {
'lucide-react': {
transform: 'lucide-react/dist/esm/icons/{{ kebabCase member }}',
},
},
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'x-dns-prefetch-control',
value: 'on',
},
{
key: 'strict-transport-security',
value: 'max-age=31536000; includeSubDomains; preload',
},
{
key: 'x-frame-options',
value: 'SAMEORIGIN',
},
{
key: 'x-content-type-options',
value: 'nosniff',
},
{
key: 'referrer-policy',
value: 'strict-origin-when-cross-origin',
},
{
key: 'permissions-policy',
value:
'accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()',
},
],
},
];
},
async rewrites() {
return [
{
source: '/ingest/:path*',
destination: 'https://eu.posthog.com/:path*',
},
];
},
};
module.exports = withContentlayer(config);

View File

@@ -1,106 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import dotenv from 'dotenv';
import fs from 'fs';
import million from 'million/compiler';
import { withContentlayer } from 'next-contentlayer';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// eslint-disable-next-line turbo/no-undeclared-env-vars
const ENV_FILES = ['.env', '.env.local', `.env.${process.env.NODE_ENV || 'development'}`];
ENV_FILES.forEach((file) => {
dotenv.config({
path: path.join(__dirname, `../../${file}`),
});
});
// !: This is a temp hack to get caveat working without placing it back in the public directory.
// !: By inlining this at build time we should be able to sign faster.
const FONT_CAVEAT_BYTES = fs.readFileSync(
path.join(__dirname, '../../packages/assets/fonts/caveat.ttf'),
);
/** @type {import('next').NextConfig} */
const config = {
experimental: {
serverActionsBodySizeLimit: '10mb',
outputFileTracingRoot: path.join(__dirname, '../../'),
},
reactStrictMode: true,
transpilePackages: [
'@documenso/assets',
'@documenso/lib',
'@documenso/tailwind-config',
'@documenso/trpc',
'@documenso/ui',
],
env: {
NEXT_PUBLIC_PROJECT: 'marketing',
FONT_CAVEAT_URI: `data:font/ttf;base64,${FONT_CAVEAT_BYTES.toString('base64')}`,
},
modularizeImports: {
'lucide-react': {
transform: 'lucide-react/dist/esm/icons/{{ kebabCase member }}',
},
},
webpack: (config, { isServer }) => {
// fixes: Module not found: Cant resolve ../build/Release/canvas.node
if (isServer) {
config.resolve.alias.canvas = false;
}
return config;
},
headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'x-dns-prefetch-control',
value: 'on',
},
{
key: 'strict-transport-security',
value: 'max-age=31536000; includeSubDomains; preload',
},
{
key: 'x-frame-options',
value: 'SAMEORIGIN',
},
{
key: 'x-content-type-options',
value: 'nosniff',
},
{
key: 'referrer-policy',
value: 'strict-origin-when-cross-origin',
},
{
key: 'permissions-policy',
value:
'accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()',
},
],
},
];
},
rewrites() {
return [
{
source: '/ingest/:path*',
destination: 'https://eu.posthog.com/:path*',
},
];
},
};
export default million.next(withContentlayer(config), {
auto: {
rsc: true,
},
});

View File

@@ -6,14 +6,12 @@
"scripts": { "scripts": {
"dev": "next dev -p 3001", "dev": "next dev -p 3001",
"build": "next build", "build": "next build",
"start": "next start -p 3001", "start": "next start",
"lint": "next lint", "lint": "next lint",
"lint:fix": "next lint --fix",
"clean": "rimraf .next && rimraf node_modules", "clean": "rimraf .next && rimraf node_modules",
"copy:pdfjs": "node ../../scripts/copy-pdfjs.cjs" "copy:pdfjs": "node ../../scripts/copy-pdfjs.cjs"
}, },
"dependencies": { "dependencies": {
"@documenso/assets": "*",
"@documenso/lib": "*", "@documenso/lib": "*",
"@documenso/tailwind-config": "*", "@documenso/tailwind-config": "*",
"@documenso/trpc": "*", "@documenso/trpc": "*",
@@ -22,11 +20,9 @@
"contentlayer": "^0.3.4", "contentlayer": "^0.3.4",
"framer-motion": "^10.12.8", "framer-motion": "^10.12.8",
"lucide-react": "^0.279.0", "lucide-react": "^0.279.0",
"luxon": "^3.4.0",
"micro": "^10.0.1", "micro": "^10.0.1",
"million": "^2.6.4", "next": "13.4.19",
"next": "14.0.0", "next-auth": "4.22.3",
"next-auth": "4.24.3",
"next-contentlayer": "^0.3.4", "next-contentlayer": "^0.3.4",
"next-plausible": "^3.10.1", "next-plausible": "^3.10.1",
"perfect-freehand": "^1.2.0", "perfect-freehand": "^1.2.0",
@@ -35,11 +31,11 @@
"react-confetti": "^6.1.0", "react-confetti": "^6.1.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-hook-form": "^7.43.9", "react-hook-form": "^7.43.9",
"react-icons": "^4.11.0", "react-icons": "^4.8.0",
"recharts": "^2.7.2", "recharts": "^2.7.2",
"sharp": "0.32.5", "sharp": "0.32.5",
"typescript": "5.2.2", "typescript": "5.1.6",
"zod": "^3.22.4" "zod": "^3.21.4"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "20.1.0", "@types/node": "20.1.0",

View File

@@ -7,7 +7,6 @@ declare namespace NodeJS {
NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID: string; NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID: string;
NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID: string; NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID: string;
NEXT_PUBLIC_STRIPE_FREE_PLAN_ID?: string;
NEXT_PRIVATE_STRIPE_API_KEY: string; NEXT_PRIVATE_STRIPE_API_KEY: string;
NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET: string; NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET: string;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 629 B

View File

@@ -1,16 +1,16 @@
import { ImageResponse } from 'next/og'; import { ImageResponse } from 'next/server';
import { allBlogPosts } from 'contentlayer/generated'; import { allBlogPosts } from 'contentlayer/generated';
export const runtime = 'edge'; export const runtime = 'edge';
export const contentType = 'image/png'; export const size = {
export const IMAGE_SIZE = {
width: 1200, width: 1200,
height: 630, height: 630,
}; };
export const contentType = 'image/png';
type BlogPostOpenGraphImageProps = { type BlogPostOpenGraphImageProps = {
params: { post: string }; params: { post: string };
}; };
@@ -25,23 +25,23 @@ export default async function BlogPostOpenGraphImage({ params }: BlogPostOpenGra
// The long urls are needed for a compiler optimisation on the Next.js side, lifting this up // The long urls are needed for a compiler optimisation on the Next.js side, lifting this up
// to a constant will break og image generation. // to a constant will break og image generation.
const [interBold, interRegular, backgroundImage, logoImage] = await Promise.all([ const [interBold, interRegular, backgroundImage, logoImage] = await Promise.all([
fetch(new URL('@documenso/assets/fonts/inter-bold.ttf', import.meta.url)).then(async (res) => fetch(new URL('./../../../../assets/inter-bold.ttf', import.meta.url)).then(async (res) =>
res.arrayBuffer(), res.arrayBuffer(),
), ),
fetch(new URL('@documenso/assets/fonts/inter-regular.ttf', import.meta.url)).then(async (res) => fetch(new URL('./../../../../assets/inter-regular.ttf', import.meta.url)).then(async (res) =>
res.arrayBuffer(), res.arrayBuffer(),
), ),
fetch(new URL('@documenso/assets/images/background-blog-og.png', import.meta.url)).then( fetch(new URL('./../../../../assets/background-blog-og.png', import.meta.url)).then(
async (res) => res.arrayBuffer(), async (res) => res.arrayBuffer(),
), ),
fetch(new URL('@documenso/assets/logo.png', import.meta.url)).then(async (res) => fetch(new URL('./../../../../../public/logo.png', import.meta.url)).then(async (res) =>
res.arrayBuffer(), res.arrayBuffer(),
), ),
]); ]);
return new ImageResponse( return new ImageResponse(
( (
<div tw="relative h-full w-full flex flex-col items-center justify-center text-center bg-white"> <div tw="relative h-full w-full flex flex-col items-center justify-center text-center">
{/* @ts-expect-error Lack of typing from ImageResponse */} {/* @ts-expect-error Lack of typing from ImageResponse */}
<img src={backgroundImage} alt="og-background" tw="absolute inset-0 w-full h-full" /> <img src={backgroundImage} alt="og-background" tw="absolute inset-0 w-full h-full" />
@@ -56,7 +56,7 @@ export default async function BlogPostOpenGraphImage({ params }: BlogPostOpenGra
</div> </div>
), ),
{ {
...IMAGE_SIZE, ...size,
fonts: [ fonts: [
{ {
name: 'Inter', name: 'Inter',

View File

@@ -32,21 +32,10 @@ export default async function ClaimedPlanPage({ searchParams = {} }: ClaimedPlan
} }
const session = await stripe.checkout.sessions.retrieve(sessionId); const session = await stripe.checkout.sessions.retrieve(sessionId);
const customerId = typeof session.customer === 'string' ? session.customer : session.customer?.id;
if (!customerId) {
redirect('/');
}
const customer = await stripe.customers.retrieve(customerId);
if (!customer || customer.deleted) {
redirect('/');
}
const user = await prisma.user.findFirst({ const user = await prisma.user.findFirst({
where: { where: {
id: Number(customer.metadata.userId), id: Number(session.client_reference_id),
}, },
}); });
@@ -176,7 +165,7 @@ export default async function ClaimedPlanPage({ searchParams = {} }: ClaimedPlan
</p> </p>
<Link <Link
href={`${process.env.NEXT_PUBLIC_WEBAPP_URL}/signin`} href={`${process.env.NEXT_PUBLIC_WEBAPP_URL}/login`}
target="_blank" target="_blank"
className="mt-4 block" className="mt-4 block"
> >

View File

@@ -2,8 +2,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { usePathname } from 'next/navigation';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Footer } from '~/components/(marketing)/footer'; import { Footer } from '~/components/(marketing)/footer';
@@ -15,7 +13,6 @@ export type MarketingLayoutProps = {
export default function MarketingLayout({ children }: MarketingLayoutProps) { export default function MarketingLayout({ children }: MarketingLayoutProps) {
const [scrollY, setScrollY] = useState(0); const [scrollY, setScrollY] = useState(0);
const pathname = usePathname();
useEffect(() => { useEffect(() => {
const onScroll = () => { const onScroll = () => {
@@ -28,11 +25,7 @@ export default function MarketingLayout({ children }: MarketingLayoutProps) {
}, []); }, []);
return ( return (
<div <div className="relative max-w-[100vw] overflow-y-auto overflow-x-hidden pt-20 md:pt-28">
className={cn('relative max-w-[100vw] pt-20 md:pt-28', {
'overflow-y-auto overflow-x-hidden': pathname !== '/singleplayer',
})}
>
<div <div
className={cn('fixed left-0 top-0 z-50 w-full bg-transparent', { className={cn('fixed left-0 top-0 z-50 w-full bg-transparent', {
'bg-background/50 backdrop-blur-md': scrollY > 5, 'bg-background/50 backdrop-blur-md': scrollY > 5,

View File

@@ -71,7 +71,7 @@ export const CapTable = ({ className, ...props }: CapTableProps) => {
</Pie> </Pie>
<Legend <Legend
formatter={(value) => { formatter={(value) => {
return <span className="text-foreground text-sm">{value}</span>; return <span className="text-sm text-black">{value}</span>;
}} }}
/> />
<Tooltip <Tooltip

View File

@@ -23,6 +23,22 @@ export const TEAM_MEMBERS = [
engagement: 'Part-Time', engagement: 'Part-Time',
joinDate: 'June 6th, 2023', joinDate: 'June 6th, 2023',
}, },
{
name: 'Florent Merian',
role: 'Marketer - III',
salary: 'Project-Based',
location: 'France',
engagement: 'Full-Time',
joinDate: 'July 10th, 2023',
},
{
name: 'Thilo Konzok',
role: 'Designer',
salary: 'Project-Based',
location: 'Germany',
engagement: 'Full-Time',
joinDate: 'April 26th, 2023',
},
{ {
name: 'David Nguyen', name: 'David Nguyen',
role: 'Software Engineer - III', role: 'Software Engineer - III',
@@ -31,22 +47,6 @@ export const TEAM_MEMBERS = [
engagement: 'Full-Time', engagement: 'Full-Time',
joinDate: 'July 26th, 2023', 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 = [ export const FUNDING_RAISED = [

View File

@@ -7,21 +7,21 @@ import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recha
import { formatMonth } from '@documenso/lib/client-only/format-month'; import { formatMonth } from '@documenso/lib/client-only/format-month';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
export type FundingRaisedProps = HTMLAttributes<HTMLDivElement> & { import { FUNDING_RAISED } from '~/app/(marketing)/open/data';
data: Record<string, string | number>[];
};
export const FundingRaised = ({ className, data, ...props }: FundingRaisedProps) => { export type FundingRaisedProps = HTMLAttributes<HTMLDivElement>;
const formattedData = data.map((item) => ({
export const FundingRaised = ({ className, ...props }: FundingRaisedProps) => {
const formattedData = FUNDING_RAISED.map((item) => ({
amount: Number(item.amount), amount: Number(item.amount),
date: formatMonth(item.date as string), date: formatMonth(item.date),
})); }));
return ( return (
<div className={cn('flex flex-col', className)} {...props}> <div className={cn('flex flex-col', className)} {...props}>
<h3 className="px-4 text-lg font-semibold">Total Funding Raised</h3> <h3 className="px-4 text-lg font-semibold">Total Funding Raised</h3>
<div className="border-border mt-2.5 flex flex-1 flex-col items-center justify-center rounded-2xl border p-6 pl-2 pt-12 shadow-sm hover:shadow"> <div className="border-border mt-2.5 flex flex-1 flex-col items-center justify-center rounded-2xl border p-4 shadow-sm hover:shadow">
<ResponsiveContainer width="100%" height={400}> <ResponsiveContainer width="100%" height={400}>
<BarChart data={formattedData} margin={{ top: 40, right: 40, bottom: 20, left: 40 }}> <BarChart data={formattedData} margin={{ top: 40, right: 40, bottom: 20, left: 40 }}>
<XAxis dataKey="date" /> <XAxis dataKey="date" />
@@ -35,9 +35,6 @@ export const FundingRaised = ({ className, data, ...props }: FundingRaisedProps)
} }
/> />
<Tooltip <Tooltip
labelStyle={{
color: 'hsl(var(--primary-foreground))',
}}
itemStyle={{ itemStyle={{
color: 'hsl(var(--primary-foreground))', color: 'hsl(var(--primary-foreground))',
}} }}
@@ -51,13 +48,7 @@ export const FundingRaised = ({ className, data, ...props }: FundingRaisedProps)
]} ]}
cursor={{ fill: 'hsl(var(--primary) / 10%)' }} cursor={{ fill: 'hsl(var(--primary) / 10%)' }}
/> />
<Bar <Bar dataKey="amount" fill="hsl(var(--primary))" label="Amount Raised" />
dataKey="amount"
fill="hsl(var(--primary))"
label="Amount Raised"
maxBarSize={60}
radius={[4, 4, 0, 0]}
/>
</BarChart> </BarChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </div>

View File

@@ -7,25 +7,26 @@ import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recha
import { formatMonth } from '@documenso/lib/client-only/format-month'; import { formatMonth } from '@documenso/lib/client-only/format-month';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
export type BarMetricProps<T extends Record<string, unknown>> = HTMLAttributes<HTMLDivElement> & { import { StargazersType } from './page';
data: T;
metricKey: keyof T[string]; export type MetricsDataKey = 'stars' | 'forks' | 'mergedPRs' | 'openIssues';
export type GithubMetricProps = HTMLAttributes<HTMLDivElement> & {
data: StargazersType;
metricKey: MetricsDataKey;
title: string; title: string;
label: string; label: string;
chartHeight?: number; chartHeight?: number;
extraInfo?: JSX.Element;
}; };
export const BarMetric = <T extends Record<string, Record<keyof T[string], unknown>>>({ export const GithubMetric = ({
className, className,
data, data,
metricKey, metricKey,
title, title,
label, label,
chartHeight = 400, chartHeight = 400,
extraInfo,
...props ...props
}: BarMetricProps<T>) => { }: GithubMetricProps) => {
const formattedData = Object.keys(data) const formattedData = Object.keys(data)
.map((key) => ({ .map((key) => ({
month: formatMonth(key), month: formatMonth(key),
@@ -35,33 +36,21 @@ export const BarMetric = <T extends Record<string, Record<keyof T[string], unkno
return ( return (
<div className={cn('flex flex-col', className)} {...props}> <div className={cn('flex flex-col', className)} {...props}>
<div className="flex items-center px-4"> <h3 className="px-4 text-lg font-semibold">{title}</h3>
<h3 className="text-lg font-semibold">{title}</h3>
<span>{extraInfo}</span>
</div>
<div className="border-border mt-2.5 flex flex-1 items-center justify-center rounded-2xl border p-6 pl-2 pt-12 shadow-sm hover:shadow"> <div className="border-border mt-2.5 flex flex-1 items-center justify-center rounded-2xl border pr-2 shadow-sm hover:shadow">
<ResponsiveContainer width="100%" height={chartHeight}> <ResponsiveContainer width="100%" height={chartHeight}>
<BarChart data={formattedData}> <BarChart data={formattedData} margin={{ top: 30, right: 20 }}>
<XAxis dataKey="month" /> <XAxis dataKey="month" />
<YAxis /> <YAxis />
<Tooltip <Tooltip
labelStyle={{
color: 'hsl(var(--primary-foreground))',
}}
itemStyle={{ itemStyle={{
color: 'hsl(var(--primary-foreground))', color: 'hsl(var(--primary-foreground))',
}} }}
formatter={(value) => [Number(value), label]} formatter={(value) => [Number(value), label]}
cursor={{ fill: 'hsl(var(--primary) / 10%)' }} cursor={{ fill: 'hsl(var(--primary) / 10%)' }}
/> />
<Bar <Bar dataKey={metricKey} fill="hsl(var(--primary))" label={label} />
dataKey={metricKey as string}
maxBarSize={60}
fill="hsl(var(--primary))"
label={label}
radius={[4, 4, 0, 0]}
/>
</BarChart> </BarChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </div>

View File

@@ -1,51 +0,0 @@
'use client';
import { DateTime } from 'luxon';
import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
import { GetUserMonthlyGrowthResult } from '@documenso/lib/server-only/user/get-user-monthly-growth';
import { cn } from '@documenso/ui/lib/utils';
export type MonthlyNewUsersChartProps = {
className?: string;
data: GetUserMonthlyGrowthResult;
};
export const MonthlyNewUsersChart = ({ className, data }: MonthlyNewUsersChartProps) => {
const formattedData = [...data].reverse().map(({ month, count }) => {
return {
month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLL'),
count: Number(count),
};
});
return (
<div className={cn('flex flex-col', className)}>
<div className="flex items-center px-4">
<h3 className="text-lg font-semibold">Monthly New Users</h3>
</div>
<div className="border-border mt-2.5 flex flex-1 items-center justify-center rounded-2xl border p-6 pl-2 pt-12 shadow-sm hover:shadow">
<ResponsiveContainer width="100%" height={400}>
<BarChart data={formattedData}>
<XAxis dataKey="month" />
<YAxis />
<Tooltip
formatter={(value) => [Number(value).toLocaleString('en-US'), 'New Users']}
cursor={{ fill: 'hsl(var(--primary) / 10%)' }}
/>
<Bar
dataKey="count"
fill="hsl(var(--primary))"
radius={[4, 4, 0, 0]}
maxBarSize={60}
label="New Users"
/>
</BarChart>
</ResponsiveContainer>
</div>
</div>
);
};

View File

@@ -1,51 +0,0 @@
'use client';
import { DateTime } from 'luxon';
import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
import { GetUserMonthlyGrowthResult } from '@documenso/lib/server-only/user/get-user-monthly-growth';
import { cn } from '@documenso/ui/lib/utils';
export type MonthlyTotalUsersChartProps = {
className?: string;
data: GetUserMonthlyGrowthResult;
};
export const MonthlyTotalUsersChart = ({ className, data }: MonthlyTotalUsersChartProps) => {
const formattedData = [...data].reverse().map(({ month, cume_count: count }) => {
return {
month: DateTime.fromFormat(month, 'yyyy-MM').toFormat('LLL'),
count: Number(count),
};
});
return (
<div className={cn('flex flex-col', className)}>
<div className="flex items-center px-4">
<h3 className="text-lg font-semibold">Monthly Total Users</h3>
</div>
<div className="border-border mt-2.5 flex flex-1 items-center justify-center rounded-2xl border p-6 pl-2 pt-12 shadow-sm hover:shadow">
<ResponsiveContainer width="100%" height={400}>
<BarChart data={formattedData}>
<XAxis dataKey="month" />
<YAxis />
<Tooltip
formatter={(value) => [Number(value).toLocaleString('en-US'), 'Total Users']}
cursor={{ fill: 'hsl(var(--primary) / 10%)' }}
/>
<Bar
dataKey="count"
fill="hsl(var(--primary))"
radius={[4, 4, 0, 0]}
maxBarSize={60}
label="Total Users"
/>
</BarChart>
</ResponsiveContainer>
</div>
</div>
);
};

View File

@@ -1,31 +1,15 @@
import { z } from 'zod'; import { z } from 'zod';
import { getUserMonthlyGrowth } from '@documenso/lib/server-only/user/get-user-monthly-growth';
import { FUNDING_RAISED } from '~/app/(marketing)/open/data';
import { MetricCard } from '~/app/(marketing)/open/metric-card'; import { MetricCard } from '~/app/(marketing)/open/metric-card';
import { SalaryBands } from '~/app/(marketing)/open/salary-bands'; import { SalaryBands } from '~/app/(marketing)/open/salary-bands';
import { BarMetric } from './bar-metrics';
import { CapTable } from './cap-table'; import { CapTable } from './cap-table';
import { FundingRaised } from './funding-raised'; import { FundingRaised } from './funding-raised';
import { MonthlyNewUsersChart } from './monthly-new-users-chart'; import { GithubMetric } from './gh-metrics';
import { MonthlyTotalUsersChart } from './monthly-total-users-chart';
import { TeamMembers } from './team-members'; import { TeamMembers } from './team-members';
import { OpenPageTooltip } from './tooltip';
export const revalidate = 3600; export const revalidate = 3600;
export const dynamic = 'force-dynamic';
const GITHUB_HEADERS: Record<string, string> = {
accept: 'application/vnd.github.v3+json',
};
if (process.env.NEXT_PRIVATE_GITHUB_TOKEN) {
GITHUB_HEADERS.authorization = `Bearer ${process.env.NEXT_PRIVATE_GITHUB_TOKEN}`;
}
const ZGithubStatsResponse = z.object({ const ZGithubStatsResponse = z.object({
stargazers_count: z.number(), stargazers_count: z.number(),
forks_count: z.number(), forks_count: z.number(),
@@ -36,10 +20,6 @@ const ZMergedPullRequestsResponse = z.object({
total_count: z.number(), total_count: z.number(),
}); });
const ZOpenIssuesResponse = z.object({
total_count: z.number(),
});
const ZStargazersLiveResponse = z.record( const ZStargazersLiveResponse = z.record(
z.object({ z.object({
stars: z.number(), stars: z.number(),
@@ -49,89 +29,41 @@ const ZStargazersLiveResponse = z.record(
}), }),
); );
const ZEarlyAdoptersResponse = z.record(
z.object({
id: z.number(),
time: z.string().datetime(),
earlyAdopters: z.number(),
}),
);
export type StargazersType = z.infer<typeof ZStargazersLiveResponse>; export type StargazersType = z.infer<typeof ZStargazersLiveResponse>;
export type EarlyAdoptersType = z.infer<typeof ZEarlyAdoptersResponse>;
const fetchGithubStats = async () => { // const ZOpenPullRequestsResponse = ZMergedPullRequestsResponse;
return await fetch('https://api.github.com/repos/documenso/documenso', {
export default async function OpenPage() {
const {
forks_count: forksCount,
open_issues: openIssues,
stargazers_count: stargazersCount,
} = await fetch('https://api.github.com/repos/documenso/documenso', {
headers: { headers: {
...GITHUB_HEADERS, accept: 'application/vnd.github.v3+json',
}, },
}) })
.then(async (res) => res.json()) .then(async (res) => res.json())
.then((res) => ZGithubStatsResponse.parse(res)); .then((res) => ZGithubStatsResponse.parse(res));
};
const fetchOpenIssues = async () => { const { total_count: mergedPullRequests } = await fetch(
return await fetch(
'https://api.github.com/search/issues?q=repo:documenso/documenso+type:issue+state:open&page=0&per_page=1',
{
headers: {
...GITHUB_HEADERS,
},
},
)
.then(async (res) => res.json())
.then((res) => ZOpenIssuesResponse.parse(res));
};
const fetchMergedPullRequests = async () => {
return await fetch(
'https://api.github.com/search/issues?q=repo:documenso/documenso/+is:pr+merged:>=2010-01-01&page=0&per_page=1', 'https://api.github.com/search/issues?q=repo:documenso/documenso/+is:pr+merged:>=2010-01-01&page=0&per_page=1',
{ {
headers: { headers: {
...GITHUB_HEADERS, accept: 'application/vnd.github.v3+json',
}, },
}, },
) )
.then(async (res) => res.json()) .then(async (res) => res.json())
.then((res) => ZMergedPullRequestsResponse.parse(res)); .then((res) => ZMergedPullRequestsResponse.parse(res));
};
const fetchStargazers = async () => { const STARGAZERS_DATA = await fetch('https://stargrazer-live.onrender.com/api/stats', {
return await fetch('https://stargrazer-live.onrender.com/api/stats', {
headers: { headers: {
accept: 'application/json', accept: 'application/json',
}, },
}) })
.then(async (res) => res.json()) .then(async (res) => res.json())
.then((res) => ZStargazersLiveResponse.parse(res)); .then((res) => ZStargazersLiveResponse.parse(res));
};
const fetchEarlyAdopters = async () => {
return await fetch('https://stargrazer-live.onrender.com/api/stats/stripe', {
headers: {
accept: 'application/json',
},
})
.then(async (res) => res.json())
.then((res) => ZEarlyAdoptersResponse.parse(res));
};
export default async function OpenPage() {
const [
{ forks_count: forksCount, stargazers_count: stargazersCount },
{ total_count: openIssues },
{ total_count: mergedPullRequests },
STARGAZERS_DATA,
EARLY_ADOPTERS_DATA,
] = await Promise.all([
fetchGithubStats(),
fetchOpenIssues(),
fetchMergedPullRequests(),
fetchStargazers(),
fetchEarlyAdopters(),
]);
const MONTHLY_USERS = await getUserMonthlyGrowth();
return ( return (
<div className="mx-auto mt-6 max-w-screen-lg sm:mt-12"> <div className="mx-auto mt-6 max-w-screen-lg sm:mt-12">
@@ -173,22 +105,12 @@ export default async function OpenPage() {
<TeamMembers className="col-span-12" /> <TeamMembers className="col-span-12" />
<SalaryBands className="col-span-12" /> <SalaryBands className="col-span-12 lg:col-span-6" />
<FundingRaised data={FUNDING_RAISED} className="col-span-12 lg:col-span-6" /> <FundingRaised className="col-span-12 lg:col-span-6" />
<CapTable className="col-span-12 lg:col-span-6" /> <CapTable className="col-span-12 lg:col-span-6" />
<GithubMetric
<BarMetric<EarlyAdoptersType>
data={EARLY_ADOPTERS_DATA}
metricKey="earlyAdopters"
title="Early Adopters"
label="Early Adopters"
className="col-span-12 lg:col-span-6"
extraInfo={<OpenPageTooltip />}
/>
<BarMetric<StargazersType>
data={STARGAZERS_DATA} data={STARGAZERS_DATA}
metricKey="stars" metricKey="stars"
title="Github: Total Stars" title="Github: Total Stars"
@@ -196,36 +118,31 @@ export default async function OpenPage() {
className="col-span-12 lg:col-span-6" className="col-span-12 lg:col-span-6"
/> />
<BarMetric<StargazersType> <GithubMetric
data={STARGAZERS_DATA} data={STARGAZERS_DATA}
metricKey="mergedPRs" metricKey="mergedPRs"
title="Github: Total Merged PRs" title="Github: Total Merged PRs"
label="Merged PRs" label="Merged PRs"
chartHeight={300} chartHeight={300}
className="col-span-12 lg:col-span-6" className="col-span-12 lg:col-span-4"
/> />
<GithubMetric
<BarMetric<StargazersType>
data={STARGAZERS_DATA} data={STARGAZERS_DATA}
metricKey="forks" metricKey="forks"
title="Github: Total Forks" title="Github: Total Forks"
label="Forks" label="Forks"
chartHeight={300} chartHeight={300}
className="col-span-12 lg:col-span-6" className="col-span-12 lg:col-span-4"
/> />
<GithubMetric
<BarMetric<StargazersType>
data={STARGAZERS_DATA} data={STARGAZERS_DATA}
metricKey="openIssues" metricKey="openIssues"
title="Github: Total Open Issues" title="Github: Total Open Issues"
label="Open Issues" label="Open Issues"
chartHeight={300} chartHeight={300}
className="col-span-12 lg:col-span-6" className="col-span-12 lg:col-span-4"
/> />
<MonthlyTotalUsersChart data={MONTHLY_USERS} className="col-span-12 lg:col-span-6" />
<MonthlyNewUsersChart data={MONTHLY_USERS} className="col-span-12 lg:col-span-6" />
<div className="col-span-12 mt-12 flex flex-col items-center justify-center"> <div className="col-span-12 mt-12 flex flex-col items-center justify-center">
<h2 className="text-2xl font-bold">Where's the rest?</h2> <h2 className="text-2xl font-bold">Where's the rest?</h2>

View File

@@ -1,40 +0,0 @@
import React from 'react';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@documenso/ui/primitives/tooltip';
export function OpenPageTooltip() {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
className="ml-2 mt-2.5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.49991 0.876892C3.84222 0.876892 0.877075 3.84204 0.877075 7.49972C0.877075 11.1574 3.84222 14.1226 7.49991 14.1226C11.1576 14.1226 14.1227 11.1574 14.1227 7.49972C14.1227 3.84204 11.1576 0.876892 7.49991 0.876892ZM1.82707 7.49972C1.82707 4.36671 4.36689 1.82689 7.49991 1.82689C10.6329 1.82689 13.1727 4.36671 13.1727 7.49972C13.1727 10.6327 10.6329 13.1726 7.49991 13.1726C4.36689 13.1726 1.82707 10.6327 1.82707 7.49972ZM8.24992 4.49999C8.24992 4.9142 7.91413 5.24999 7.49992 5.24999C7.08571 5.24999 6.74992 4.9142 6.74992 4.49999C6.74992 4.08577 7.08571 3.74999 7.49992 3.74999C7.91413 3.74999 8.24992 4.08577 8.24992 4.49999ZM6.00003 5.99999H6.50003H7.50003C7.77618 5.99999 8.00003 6.22384 8.00003 6.49999V9.99999H8.50003H9.00003V11H8.50003H7.50003H6.50003H6.00003V9.99999H6.50003H7.00003V6.99999H6.50003H6.00003V5.99999Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
</TooltipTrigger>
<TooltipContent>
<p>
August and earlier: Active subscribers. September and beyond: Numbers of active
subscriptions.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}

View File

@@ -2,7 +2,7 @@ import Image from 'next/image';
import { z } from 'zod'; import { z } from 'zod';
import backgroundPattern from '@documenso/assets/images/background-pattern.png'; import backgroundPattern from '~/assets/background-pattern.png';
import { OSSFriendsContainer } from './container'; import { OSSFriendsContainer } from './container';
import { TOSSFriendsSchema, ZOSSFriendsSchema } from './schema'; import { TOSSFriendsSchema, ZOSSFriendsSchema } from './schema';

View File

@@ -6,7 +6,6 @@ import {
AccordionItem, AccordionItem,
AccordionTrigger, AccordionTrigger,
} from '@documenso/ui/primitives/accordion'; } from '@documenso/ui/primitives/accordion';
import { Button } from '@documenso/ui/primitives/button';
import { PricingTable } from '~/components/(marketing)/pricing-table'; import { PricingTable } from '~/components/(marketing)/pricing-table';
@@ -35,26 +34,6 @@ export default function PricingPage() {
<PricingTable /> <PricingTable />
</div> </div>
<div className="mx-auto mt-36 max-w-2xl">
<h2 className="text-center text-2xl font-semibold">
None of these work for you? Try self-hosting!
</h2>
<p className="text-muted-foreground mt-4 text-center leading-relaxed">
Our self-hosted option is great for small teams and individuals who need a simple
solution. You can use our docker based setup to get started in minutes. Take control with
full customizability and data ownership.
</p>
<div className="mt-4 flex justify-center">
<Button variant="outline" size="lg" className="rounded-full hover:cursor-pointer" asChild>
<Link href="https://github.com/documenso/documenso" target="_blank">
Get Started
</Link>
</Button>
</div>
</div>
<div className="mx-auto mt-36 max-w-2xl"> <div className="mx-auto mt-36 max-w-2xl">
{/* FAQ Section */} {/* FAQ Section */}
@@ -69,9 +48,9 @@ export default function PricingPage() {
<AccordionContent className="text-muted-foreground max-w-prose text-sm leading-relaxed"> <AccordionContent className="text-muted-foreground max-w-prose text-sm leading-relaxed">
You can self-host Documenso for free or use our ready-to-use hosted version. The You can self-host Documenso for free or use our ready-to-use hosted version. The
hosted version comes with additional support, painless scalability and more. Early hosted version comes with additional support, painless scalability and more. Early
adopters will get access to all features we build this year, for no additional cost! adopters of the community plan will get access to all features we build this year, for
Forever! Yes, that includes multiple users per account later. If you want Documenso no additional cost! Forever! Yes, that includes multiple users per account later. If
for your enterprise, we are happy to talk about your needs. you want Documenso for your enterprise, we are happy to talk about your needs.
</AccordionContent> </AccordionContent>
</AccordionItem> </AccordionItem>
@@ -117,10 +96,10 @@ export default function PricingPage() {
and join our{' '} and join our{' '}
<Link <Link
className="text-documenso-700 font-bold" className="text-documenso-700 font-bold"
href="https://documen.so/discord" href="https://join.slack.com/t/documenso/shared_invite/zt-1vibm8txi-DqsDFtdp44Hn2H5lc~RpPQ"
target="_blank" target="_blank"
> >
Discord Community Slack Community
</Link>{' '} </Link>{' '}
to keep up to date, on what the current priorities are. In any case, we are an open to keep up to date, on what the current priorities are. In any case, we are an open
community and welcome all input, technical and non-technical ❤️ community and welcome all input, technical and non-technical ❤️
@@ -168,10 +147,10 @@ export default function PricingPage() {
or{' '} or{' '}
<a <a
className="text-documenso-700 font-bold" className="text-documenso-700 font-bold"
href="https://documen.so/discord" href="https://join.slack.com/t/documenso/shared_invite/zt-1vibm8txi-DqsDFtdp44Hn2H5lc~RpPQ"
target="_blank" target="_blank"
> >
in our Discord-Support-Channel in our Slack-Support-Channel
</a>{' '} </a>{' '}
please message either Lucas or Timur to get added to the channel if you are not please message either Lucas or Timur to get added to the channel if you are not
already a member. already a member.

View File

@@ -1,7 +1,6 @@
import { notFound } from 'next/navigation'; import { notFound } from 'next/navigation';
import { getDocumentAndRecipientByToken } from '@documenso/lib/server-only/document/get-document-by-token'; import { getDocumentAndRecipientByToken } from '@documenso/lib/server-only/document/get-document-by-token';
import { getRecipientSignatures } from '@documenso/lib/server-only/recipient/get-recipient-signatures';
import { DocumentStatus } from '@documenso/prisma/client'; import { DocumentStatus } from '@documenso/prisma/client';
import { SinglePlayerModeSuccess } from '~/components/(marketing)/single-player-mode/single-player-mode-success'; import { SinglePlayerModeSuccess } from '~/components/(marketing)/single-player-mode/single-player-mode-success';
@@ -27,7 +26,5 @@ export default async function SinglePlayerModeSuccessPage({
return notFound(); return notFound();
} }
const signatures = await getRecipientSignatures({ recipientId: document.Recipient.id }); return <SinglePlayerModeSuccess document={document} />;
return <SinglePlayerModeSuccess document={document} signatures={signatures} />;
} }

View File

@@ -8,29 +8,26 @@ import { useRouter } from 'next/navigation';
import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics';
import { base64 } from '@documenso/lib/universal/base64'; import { base64 } from '@documenso/lib/universal/base64';
import { putFile } from '@documenso/lib/universal/upload/put-file'; import { putFile } from '@documenso/lib/universal/upload/put-file';
import type { Field, Recipient } from '@documenso/prisma/client'; import { Field, Prisma, Recipient } from '@documenso/prisma/client';
import { DocumentDataType, Prisma } from '@documenso/prisma/client';
import { trpc } from '@documenso/trpc/react';
import { Card, CardContent } from '@documenso/ui/primitives/card'; import { Card, CardContent } from '@documenso/ui/primitives/card';
import { DocumentDropzone } from '@documenso/ui/primitives/document-dropzone'; import { DocumentDropzone } from '@documenso/ui/primitives/document-dropzone';
import { AddFieldsFormPartial } from '@documenso/ui/primitives/document-flow/add-fields'; import { AddFieldsFormPartial } from '@documenso/ui/primitives/document-flow/add-fields';
import type { TAddFieldsFormSchema } from '@documenso/ui/primitives/document-flow/add-fields.types'; import { TAddFieldsFormSchema } from '@documenso/ui/primitives/document-flow/add-fields.types';
import { AddSignatureFormPartial } from '@documenso/ui/primitives/document-flow/add-signature'; import { AddSignatureFormPartial } from '@documenso/ui/primitives/document-flow/add-signature';
import type { TAddSignatureFormSchema } from '@documenso/ui/primitives/document-flow/add-signature.types'; import { TAddSignatureFormSchema } from '@documenso/ui/primitives/document-flow/add-signature.types';
import { import {
DocumentFlowFormContainer, DocumentFlowFormContainer,
DocumentFlowFormContainerHeader, DocumentFlowFormContainerHeader,
} from '@documenso/ui/primitives/document-flow/document-flow-root'; } from '@documenso/ui/primitives/document-flow/document-flow-root';
import type { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types'; import { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types';
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer'; import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
import { useToast } from '@documenso/ui/primitives/use-toast'; import { useToast } from '@documenso/ui/primitives/use-toast';
import { createSinglePlayerDocument } from '~/components/(marketing)/single-player-mode/create-single-player-document.action';
type SinglePlayerModeStep = 'fields' | 'sign'; type SinglePlayerModeStep = 'fields' | 'sign';
// !: This entire file is a hack to get around failed prerendering of export default function SinglePlayerModePage() {
// !: the Single Player Mode page. This regression was introduced during
// !: the upgrade of Next.js to v13.5.x.
export const SinglePlayerClient = () => {
const analytics = useAnalytics(); const analytics = useAnalytics();
const router = useRouter(); const router = useRouter();
@@ -41,9 +38,6 @@ export const SinglePlayerClient = () => {
const [step, setStep] = useState<SinglePlayerModeStep>('fields'); const [step, setStep] = useState<SinglePlayerModeStep>('fields');
const [fields, setFields] = useState<Field[]>([]); const [fields, setFields] = useState<Field[]>([]);
const { mutateAsync: createSinglePlayerDocument } =
trpc.singleplayer.createSinglePlayerDocument.useMutation();
const documentFlow: Record<SinglePlayerModeStep, DocumentFlowStep> = { const documentFlow: Record<SinglePlayerModeStep, DocumentFlowStep> = {
fields: { fields: {
title: 'Add document', title: 'Add document',
@@ -136,7 +130,7 @@ export const SinglePlayerClient = () => {
signer: data.email, signer: data.email,
}); });
router.push(`/singleplayer/${documentToken}/success`); router.push(`/single-player-mode/${documentToken}/success`);
} catch { } catch {
toast({ toast({
title: 'Something went wrong', title: 'Something went wrong',
@@ -162,11 +156,11 @@ export const SinglePlayerClient = () => {
const onFileDrop = async (file: File) => { const onFileDrop = async (file: File) => {
try { try {
const arrayBuffer = await file.arrayBuffer(); const arrayBuffer = await file.arrayBuffer();
const fileBase64 = base64.encode(new Uint8Array(arrayBuffer)); const base64String = base64.encode(new Uint8Array(arrayBuffer));
setUploadedFile({ setUploadedFile({
file, file,
fileBase64, fileBase64: `data:application/pdf;base64,${base64String}`,
}); });
analytics.capture('Marketing: SPM - Document uploaded'); analytics.capture('Marketing: SPM - Document uploaded');
@@ -185,15 +179,7 @@ export const SinglePlayerClient = () => {
<h1 className="text-3xl font-bold lg:text-5xl">Single Player Mode</h1> <h1 className="text-3xl font-bold lg:text-5xl">Single Player Mode</h1>
<p className="text-foreground mx-auto mt-4 max-w-[50ch] text-lg leading-normal"> <p className="text-foreground mx-auto mt-4 max-w-[50ch] text-lg leading-normal">
Create a{' '} View our{' '}
<Link
href={`${process.env.NEXT_PUBLIC_WEBAPP_URL}/signup`}
target="_blank"
className="hover:text-foreground/80 font-semibold transition-colors"
>
free account
</Link>{' '}
or view our{' '}
<Link <Link
href={'/pricing'} href={'/pricing'}
target="_blank" target="_blank"
@@ -210,14 +196,7 @@ export const SinglePlayerClient = () => {
{uploadedFile ? ( {uploadedFile ? (
<Card gradient> <Card gradient>
<CardContent className="p-2"> <CardContent className="p-2">
<LazyPDFViewer <LazyPDFViewer document={uploadedFile.fileBase64} />
documentData={{
id: '',
data: uploadedFile.fileBase64,
initialData: uploadedFile.fileBase64,
type: DocumentDataType.BYTES_64,
}}
/>
</CardContent> </CardContent>
</Card> </Card>
) : ( ) : (
@@ -262,4 +241,4 @@ export const SinglePlayerClient = () => {
</div> </div>
</div> </div>
); );
}; }

View File

@@ -1,10 +0,0 @@
import { SinglePlayerClient } from './client';
export const revalidate = 0;
// !: This entire file is a hack to get around failed prerendering of
// !: the Single Player Mode page. This regression was introduced during
// !: the upgrade of Next.js to v13.5.x.
export default function SingleplayerPage() {
return <SinglePlayerClient />;
}

View File

@@ -4,7 +4,6 @@ import { Caveat, Inter } from 'next/font/google';
import { FeatureFlagProvider } from '@documenso/lib/client-only/providers/feature-flag'; import { FeatureFlagProvider } from '@documenso/lib/client-only/providers/feature-flag';
import { getAllAnonymousFlags } from '@documenso/lib/universal/get-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 { cn } from '@documenso/ui/lib/utils';
import { Toaster } from '@documenso/ui/primitives/toaster'; import { Toaster } from '@documenso/ui/primitives/toaster';
@@ -64,9 +63,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
<body> <body>
<FeatureFlagProvider initialFlags={flags}> <FeatureFlagProvider initialFlags={flags}>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem> <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<PlausibleProvider> <PlausibleProvider>{children}</PlausibleProvider>
<TrpcProvider>{children}</TrpcProvider>
</PlausibleProvider>
</ThemeProvider> </ThemeProvider>
</FeatureFlagProvider> </FeatureFlagProvider>

View File

@@ -7,10 +7,11 @@ import { useRouter } from 'next/navigation';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { ChevronLeft } from 'lucide-react'; import { ChevronLeft } from 'lucide-react';
import backgroundPattern from '@documenso/assets/images/background-pattern.png';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button'; import { Button } from '@documenso/ui/primitives/button';
import backgroundPattern from '~/assets/background-pattern.png';
export default function NotFound() { export default function NotFound() {
const router = useRouter(); const router = useRouter();

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 896 KiB

After

Width:  |  Height:  |  Size: 896 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 337 KiB

After

Width:  |  Height:  |  Size: 337 KiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 251 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 394 KiB

After

Width:  |  Height:  |  Size: 394 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 254 KiB

After

Width:  |  Height:  |  Size: 254 KiB

View File

Before

Width:  |  Height:  |  Size: 20 MiB

After

Width:  |  Height:  |  Size: 20 MiB

View File

@@ -2,8 +2,8 @@
import Link from 'next/link'; import Link from 'next/link';
import { Github } from 'lucide-react';
import { usePlausible } from 'next-plausible'; import { usePlausible } from 'next-plausible';
import { LuGithub } from 'react-icons/lu';
import { Button } from '@documenso/ui/primitives/button'; import { Button } from '@documenso/ui/primitives/button';
@@ -40,7 +40,7 @@ export const Callout = ({ starCount }: CalloutProps) => {
className="rounded-full bg-transparent backdrop-blur-sm" className="rounded-full bg-transparent backdrop-blur-sm"
onClick={onSignUpClick} onClick={onSignUpClick}
> >
Get the Early Adopters Plan Get the Community Plan
<span className="bg-primary dark:text-background -mr-2.5 ml-2.5 rounded-full px-2 py-1.5 text-xs"> <span className="bg-primary dark:text-background -mr-2.5 ml-2.5 rounded-full px-2 py-1.5 text-xs">
$30/mo. forever! $30/mo. forever!
</span> </span>
@@ -52,7 +52,7 @@ export const Callout = ({ starCount }: CalloutProps) => {
onClick={() => event('view-github')} onClick={() => event('view-github')}
> >
<Button variant="outline" className="rounded-full bg-transparent backdrop-blur-sm"> <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 Star on Github
{starCount && starCount > 0 && ( {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"> <span className="bg-primary dark:text-background -mr-2.5 ml-2.5 rounded-full px-2 py-1.5 text-xs">

View File

@@ -1,6 +1,6 @@
'use client'; 'use client';
import React, { useEffect, useState } from 'react'; import React, { useState } from 'react';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
@@ -30,7 +30,7 @@ import { claimPlan } from '~/api/claim-plan/fetcher';
import { FormErrorMessage } from '../form/form-error-message'; import { FormErrorMessage } from '../form/form-error-message';
export const ZClaimPlanDialogFormSchema = z.object({ export const ZClaimPlanDialogFormSchema = z.object({
name: z.string().trim().min(3, { message: 'Please enter a valid name.' }), name: z.string().min(3),
email: z.string().email(), email: z.string().email(),
}); });
@@ -55,8 +55,8 @@ export const ClaimPlanDialog = ({ className, planId, children }: ClaimPlanDialog
register, register,
handleSubmit, handleSubmit,
formState: { errors, isSubmitting }, formState: { errors, isSubmitting },
reset,
} = useForm<TClaimPlanDialogFormSchema>({ } = useForm<TClaimPlanDialogFormSchema>({
mode: 'onBlur',
defaultValues: { defaultValues: {
name: params?.get('name') ?? '', name: params?.get('name') ?? '',
email: params?.get('email') ?? '', email: params?.get('email') ?? '',
@@ -91,12 +91,6 @@ export const ClaimPlanDialog = ({ className, planId, children }: ClaimPlanDialog
} }
}; };
useEffect(() => {
if (!isSubmitting && !open) {
reset();
}
}, [open]);
return ( return (
<Dialog open={open} onOpenChange={(value) => !isSubmitting && setOpen(value)}> <Dialog open={open} onOpenChange={(value) => !isSubmitting && setOpen(value)}>
<DialogTrigger asChild>{children}</DialogTrigger> <DialogTrigger asChild>{children}</DialogTrigger>
@@ -145,7 +139,7 @@ export const ClaimPlanDialog = ({ className, planId, children }: ClaimPlanDialog
</div> </div>
<Button type="submit" size="lg" loading={isSubmitting}> <Button type="submit" size="lg" loading={isSubmitting}>
Claim the early adopters Plan ( Claim the Community Plan (
{/* eslint-disable-next-line turbo/no-undeclared-env-vars */} {/* eslint-disable-next-line turbo/no-undeclared-env-vars */}
{planId === process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID {planId === process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID
? 'Monthly' ? 'Monthly'

View File

@@ -8,10 +8,10 @@ import { createPortal } from 'react-dom';
import { useIsMounted } from '@documenso/lib/client-only/hooks/use-is-mounted'; import { useIsMounted } from '@documenso/lib/client-only/hooks/use-is-mounted';
import { useWindowSize } from '@documenso/lib/client-only/hooks/use-window-size'; import { useWindowSize } from '@documenso/lib/client-only/hooks/use-window-size';
export const ConfettiScreen = ({ export default function ConfettiScreen({
numberOfPieces: numberOfPiecesProp = 200, numberOfPieces: numberOfPiecesProp = 200,
...props ...props
}: React.ComponentPropsWithoutRef<typeof Confetti> & { duration?: number }) => { }: React.ComponentPropsWithoutRef<typeof Confetti> & { duration?: number }) {
const isMounted = useIsMounted(); const isMounted = useIsMounted();
const { width, height } = useWindowSize(); const { width, height } = useWindowSize();
@@ -43,4 +43,4 @@ export const ConfettiScreen = ({
/>, />,
document.body, document.body,
); );
}; }

View File

@@ -2,13 +2,14 @@ import { HTMLAttributes } from 'react';
import Image from 'next/image'; import Image from 'next/image';
import backgroundPattern from '@documenso/assets/images/background-pattern.png';
import cardBeautifulFigure from '@documenso/assets/images/card-beautiful-figure.png';
import cardFastFigure from '@documenso/assets/images/card-fast-figure.png';
import cardSmartFigure from '@documenso/assets/images/card-smart-figure.png';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Card, CardContent } from '@documenso/ui/primitives/card'; import { Card, CardContent } from '@documenso/ui/primitives/card';
import backgroundPattern from '~/assets/background-pattern.png';
import cardBeautifulFigure from '~/assets/card-beautiful-figure.png';
import cardFastFigure from '~/assets/card-fast-figure.png';
import cardSmartFigure from '~/assets/card-smart-figure.png';
export type FasterSmarterBeautifulBentoProps = HTMLAttributes<HTMLDivElement>; export type FasterSmarterBeautifulBentoProps = HTMLAttributes<HTMLDivElement>;
export const FasterSmarterBeautifulBento = ({ export const FasterSmarterBeautifulBento = ({

View File

@@ -1,47 +1,44 @@
'use client'; 'use client';
import type { HTMLAttributes } from 'react'; import { HTMLAttributes } from 'react';
import Image from 'next/image'; import Image from 'next/image';
import Link from 'next/link'; import Link from 'next/link';
import { FaXTwitter } from 'react-icons/fa6'; import { Github, MessagesSquare, Moon, Sun, Twitter } from 'lucide-react';
import { LiaDiscord } from 'react-icons/lia'; import { useTheme } from 'next-themes';
import { LuGithub } from 'react-icons/lu';
import LogoImage from '@documenso/assets/logo.png';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { ThemeSwitcher } from '@documenso/ui/primitives/theme-switcher';
export type FooterProps = HTMLAttributes<HTMLDivElement>; export type FooterProps = HTMLAttributes<HTMLDivElement>;
const SOCIAL_LINKS = [ const SOCIAL_LINKS = [
{ href: 'https://twitter.com/documenso', icon: <FaXTwitter className="h-6 w-6" /> }, { href: 'https://twitter.com/documenso', icon: <Twitter className="h-6 w-6" /> },
{ href: 'https://github.com/documenso/documenso', icon: <LuGithub className="h-6 w-6" /> }, { href: 'https://github.com/documenso/documenso', icon: <Github className="h-6 w-6" /> },
{ href: 'https://documen.so/discord', icon: <LiaDiscord className="h-7 w-7" /> }, { href: 'https://documen.so/discord', icon: <MessagesSquare className="h-6 w-6" /> },
]; ];
const FOOTER_LINKS = [ const FOOTER_LINKS = [
{ href: '/pricing', text: 'Pricing' }, { href: '/pricing', text: 'Pricing' },
{ href: '/singleplayer', text: 'Singleplayer' }, { href: '/single-player-mode', text: 'Single Player Mode' },
{ href: '/blog', text: 'Blog' }, { href: '/blog', text: 'Blog' },
{ href: '/design-system', text: 'Design' }, { href: '/open', text: 'Open' },
{ href: '/open', text: 'Open Startup' },
{ href: 'https://shop.documenso.com', text: 'Shop', target: '_blank' }, { href: 'https://shop.documenso.com', text: 'Shop', target: '_blank' },
{ href: 'https://status.documenso.com', text: 'Status', target: '_blank' }, { href: 'https://status.documenso.com', text: 'Status', target: '_blank' },
{ href: 'mailto:support@documenso.com', text: 'Support', target: '_blank' }, { href: 'mailto:support@documenso.com', text: 'Support' },
{ href: '/oss-friends', text: 'OSS Friends' },
{ href: '/privacy', text: 'Privacy' }, { href: '/privacy', text: 'Privacy' },
]; ];
export const Footer = ({ className, ...props }: FooterProps) => { export const Footer = ({ className, ...props }: FooterProps) => {
const { setTheme } = useTheme();
return ( return (
<div className={cn('border-t py-12', className)} {...props}> <div className={cn('border-t py-12', className)} {...props}>
<div className="mx-auto flex w-full max-w-screen-xl flex-wrap items-start justify-between gap-8 px-8"> <div className="mx-auto flex w-full max-w-screen-xl flex-wrap items-start justify-between gap-8 px-8">
<div> <div>
<Link href="/"> <Link href="/">
<Image <Image
src={LogoImage} src="/logo.png"
alt="Documenso Logo" alt="Documenso Logo"
className="dark:invert" className="dark:invert"
width={170} width={170}
@@ -63,7 +60,7 @@ export const Footer = ({ className, ...props }: FooterProps) => {
</div> </div>
</div> </div>
<div className="grid max-w-xs flex-1 grid-cols-2 gap-x-4 gap-y-2"> <div className="flex flex-wrap items-center gap-x-4 gap-y-2.5">
{FOOTER_LINKS.map((link, index) => ( {FOOTER_LINKS.map((link, index) => (
<Link <Link
key={index} key={index}
@@ -76,13 +73,21 @@ export const Footer = ({ className, ...props }: FooterProps) => {
))} ))}
</div> </div>
</div> </div>
<div className="mx-auto mt-4 flex w-full max-w-screen-xl flex-wrap items-center justify-between gap-4 px-8 md:mt-12 lg:mt-24"> <div className="mx-auto mt-4 flex w-full max-w-screen-xl flex-wrap justify-between gap-4 px-8 md:mt-12 lg:mt-24">
<p className="text-muted-foreground text-sm"> <p className="text-muted-foreground text-sm">
© {new Date().getFullYear()} Documenso, Inc. All rights reserved. © {new Date().getFullYear()} Documenso, Inc. All rights reserved.
</p> </p>
<div className="flex flex-wrap"> <div className="flex flex-wrap items-center gap-x-4 gap-y-2.5">
<ThemeSwitcher /> <button type="button" className="text-muted-foreground" onClick={() => setTheme('light')}>
<Sun className="h-5 w-5" />
<span className="sr-only">Light</span>
</button>
<button type="button" className="text-muted-foreground" onClick={() => setTheme('dark')}>
<Moon className="h-5 w-5" />
<span className="sr-only">Dark</span>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,12 +1,10 @@
'use client'; 'use client';
import type { HTMLAttributes } from 'react'; import { HTMLAttributes, useState } from 'react';
import { useState } from 'react';
import Image from 'next/image'; import Image from 'next/image';
import Link from 'next/link'; import Link from 'next/link';
import LogoImage from '@documenso/assets/logo.png';
import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag'; import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
@@ -27,7 +25,7 @@ export const Header = ({ className, ...props }: HeaderProps) => {
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<Link href="/" className="z-10" onClick={() => setIsHamburgerMenuOpen(false)}> <Link href="/" className="z-10" onClick={() => setIsHamburgerMenuOpen(false)}>
<Image <Image
src={LogoImage} src="/logo.png"
alt="Documenso Logo" alt="Documenso Logo"
className="dark:invert" className="dark:invert"
width={170} width={170}
@@ -37,7 +35,7 @@ export const Header = ({ className, ...props }: HeaderProps) => {
{isSinglePlayerModeMarketingEnabled && ( {isSinglePlayerModeMarketingEnabled && (
<Link <Link
href="/singleplayer" href="/single-player-mode"
className="bg-primary dark:text-background rounded-full px-2 py-1 text-xs font-semibold sm:px-3" className="bg-primary dark:text-background rounded-full px-2 py-1 text-xs font-semibold sm:px-3"
> >
Try now! Try now!
@@ -64,11 +62,11 @@ export const Header = ({ className, ...props }: HeaderProps) => {
href="/open" href="/open"
className="text-muted-foreground hover:text-muted-foreground/80 text-sm font-semibold" className="text-muted-foreground hover:text-muted-foreground/80 text-sm font-semibold"
> >
Open Startup Open
</Link> </Link>
<Link <Link
href="https://app.documenso.com/signin" href="https://app.documenso.com/login"
target="_blank" target="_blank"
className="text-muted-foreground hover:text-muted-foreground/80 text-sm font-semibold" className="text-muted-foreground hover:text-muted-foreground/80 text-sm font-semibold"
> >

View File

@@ -4,15 +4,16 @@ import Image from 'next/image';
import Link from 'next/link'; import Link from 'next/link';
import { Variants, motion } from 'framer-motion'; import { Variants, motion } from 'framer-motion';
import { Github } from 'lucide-react';
import { usePlausible } from 'next-plausible'; import { usePlausible } from 'next-plausible';
import { LuGithub } from 'react-icons/lu';
import { match } from 'ts-pattern'; import { match } from 'ts-pattern';
import backgroundPattern from '@documenso/assets/images/background-pattern.png';
import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag'; import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button'; import { Button } from '@documenso/ui/primitives/button';
import backgroundPattern from '~/assets/background-pattern.png';
import { Widget } from './widget'; import { Widget } from './widget';
export type HeroProps = { export type HeroProps = {
@@ -113,7 +114,7 @@ export const Hero = ({ className, ...props }: HeroProps) => {
className="rounded-full bg-transparent backdrop-blur-sm" className="rounded-full bg-transparent backdrop-blur-sm"
onClick={onSignUpClick} onClick={onSignUpClick}
> >
Get the Early Adopters Plan Get the Community Plan
<span className="bg-primary dark:text-background -mr-2.5 ml-2.5 rounded-full px-2 py-1.5 text-xs"> <span className="bg-primary dark:text-background -mr-2.5 ml-2.5 rounded-full px-2 py-1.5 text-xs">
$30/mo. forever! $30/mo. forever!
</span> </span>
@@ -121,7 +122,7 @@ export const Hero = ({ className, ...props }: HeroProps) => {
<Link href="https://github.com/documenso/documenso" onClick={() => event('view-github')}> <Link href="https://github.com/documenso/documenso" onClick={() => event('view-github')}>
<Button variant="outline" className="rounded-full bg-transparent backdrop-blur-sm"> <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 Star on Github
</Button> </Button>
</Link> </Link>
@@ -133,9 +134,9 @@ export const Hero = ({ className, ...props }: HeroProps) => {
variants={HeroTitleVariants} variants={HeroTitleVariants}
initial="initial" initial="initial"
animate="animate" animate="animate"
className="border-primary bg-background hover:bg-muted mx-auto mt-8 w-60 rounded-xl border transition-colors duration-300" className="border-primary bg-background hover:bg-muted mx-auto mt-8 w-60 rounded-xl border transition duration-300"
> >
<Link href="/singleplayer" className="block px-4 py-2 text-center"> <Link href="/single-player-mode" className="block px-4 py-2 text-center">
<h2 className="text-muted-foreground text-xs font-semibold"> <h2 className="text-muted-foreground text-xs font-semibold">
Introducing Single Player Mode Introducing Single Player Mode
</h2> </h2>

View File

@@ -4,11 +4,8 @@ import Image from 'next/image';
import Link from 'next/link'; import Link from 'next/link';
import { motion, useReducedMotion } from 'framer-motion'; import { motion, useReducedMotion } from 'framer-motion';
import { FaXTwitter } from 'react-icons/fa6'; import { Github, MessagesSquare, Twitter } from 'lucide-react';
import { LiaDiscord } from 'react-icons/lia';
import { LuGithub } from 'react-icons/lu';
import LogoImage from '@documenso/assets/logo.png';
import { Sheet, SheetContent } from '@documenso/ui/primitives/sheet'; import { Sheet, SheetContent } from '@documenso/ui/primitives/sheet';
export type MobileNavigationProps = { export type MobileNavigationProps = {
@@ -18,8 +15,8 @@ export type MobileNavigationProps = {
export const MENU_NAVIGATION_LINKS = [ export const MENU_NAVIGATION_LINKS = [
{ {
href: '/singleplayer', href: '/single-player-mode',
text: 'Singleplayer', text: 'Single Player Mode',
}, },
{ {
href: '/blog', href: '/blog',
@@ -31,7 +28,7 @@ export const MENU_NAVIGATION_LINKS = [
}, },
{ {
href: '/open', href: '/open',
text: 'Open Startup', text: 'Open',
}, },
{ {
href: 'https://status.documenso.com', href: 'https://status.documenso.com',
@@ -40,14 +37,13 @@ export const MENU_NAVIGATION_LINKS = [
{ {
href: 'mailto:support@documenso.com', href: 'mailto:support@documenso.com',
text: 'Support', text: 'Support',
target: '_blank',
}, },
{ {
href: '/privacy', href: '/privacy',
text: 'Privacy', text: 'Privacy',
}, },
{ {
href: 'https://app.documenso.com/signin', href: 'https://app.documenso.com/login',
text: 'Sign in', text: 'Sign in',
}, },
]; ];
@@ -64,7 +60,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
<SheetContent className="w-full max-w-[400px]"> <SheetContent className="w-full max-w-[400px]">
<Link href="/" className="z-10" onClick={handleMenuItemClick}> <Link href="/" className="z-10" onClick={handleMenuItemClick}>
<Image <Image
src={LogoImage} src="/logo.png"
alt="Documenso Logo" alt="Documenso Logo"
className="dark:invert" className="dark:invert"
width={170} width={170}
@@ -80,7 +76,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
staggerChildren: 0.03, staggerChildren: 0.03,
}} }}
> >
{MENU_NAVIGATION_LINKS.map(({ href, text, target }) => ( {MENU_NAVIGATION_LINKS.map(({ href, text }) => (
<motion.div <motion.div
key={href} key={href}
variants={{ variants={{
@@ -102,7 +98,6 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
className="text-foreground hover:text-foreground/80 text-2xl font-semibold" className="text-foreground hover:text-foreground/80 text-2xl font-semibold"
href={href} href={href}
onClick={() => handleMenuItemClick()} onClick={() => handleMenuItemClick()}
target={target}
> >
{text} {text}
</Link> </Link>
@@ -116,7 +111,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
target="_blank" target="_blank"
className="text-foreground hover:text-foreground/80" className="text-foreground hover:text-foreground/80"
> >
<FaXTwitter className="h-6 w-6" /> <Twitter className="h-6 w-6" />
</Link> </Link>
<Link <Link
@@ -124,7 +119,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
target="_blank" target="_blank"
className="text-foreground hover:text-foreground/80" className="text-foreground hover:text-foreground/80"
> >
<LuGithub className="h-6 w-6" /> <Github className="h-6 w-6" />
</Link> </Link>
<Link <Link
@@ -132,7 +127,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
target="_blank" target="_blank"
className="text-foreground hover:text-foreground/80" className="text-foreground hover:text-foreground/80"
> >
<LiaDiscord className="h-7 w-7" /> <MessagesSquare className="h-6 w-6" />
</Link> </Link>
</div> </div>
</SheetContent> </SheetContent>

View File

@@ -2,13 +2,14 @@ import { HTMLAttributes } from 'react';
import Image from 'next/image'; import Image from 'next/image';
import backgroundPattern from '@documenso/assets/images/background-pattern.png';
import cardBuildFigure from '@documenso/assets/images/card-build-figure.png';
import cardOpenFigure from '@documenso/assets/images/card-open-figure.png';
import cardTemplateFigure from '@documenso/assets/images/card-template-figure.png';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Card, CardContent } from '@documenso/ui/primitives/card'; import { Card, CardContent } from '@documenso/ui/primitives/card';
import backgroundPattern from '~/assets/background-pattern.png';
import cardBuildFigure from '~/assets/card-build-figure.png';
import cardOpenFigure from '~/assets/card-open-figure.png';
import cardTemplateFigure from '~/assets/card-template-figure.png';
export type OpenBuildTemplateBentoProps = HTMLAttributes<HTMLDivElement>; export type OpenBuildTemplateBentoProps = HTMLAttributes<HTMLDivElement>;
export const OpenBuildTemplateBento = ({ className, ...props }: OpenBuildTemplateBentoProps) => { export const OpenBuildTemplateBento = ({ className, ...props }: OpenBuildTemplateBentoProps) => {

View File

@@ -1,8 +1,9 @@
'use client'; 'use client';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { useToast } from '@documenso/ui/primitives/use-toast'; import { useToast } from '@documenso/ui/primitives/use-toast';
import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
export type PasswordRevealProps = { export type PasswordRevealProps = {
password: string; password: string;
}; };

View File

@@ -1,6 +1,6 @@
'use client'; 'use client';
import { HTMLAttributes, useState } from 'react'; import { HTMLAttributes, useMemo, useState } from 'react';
import Link from 'next/link'; import Link from 'next/link';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
@@ -11,6 +11,8 @@ import { usePlausible } from 'next-plausible';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button'; import { Button } from '@documenso/ui/primitives/button';
import { ClaimPlanDialog } from './claim-plan-dialog';
export type PricingTableProps = HTMLAttributes<HTMLDivElement>; export type PricingTableProps = HTMLAttributes<HTMLDivElement>;
const SELECTED_PLAN_BAR_LAYOUT_ID = 'selected-plan-bar'; const SELECTED_PLAN_BAR_LAYOUT_ID = 'selected-plan-bar';
@@ -25,6 +27,14 @@ export const PricingTable = ({ className, ...props }: PricingTableProps) => {
: 'MONTHLY', : 'MONTHLY',
); );
const planId = useMemo(() => {
if (period === 'MONTHLY') {
return process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID;
}
return process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID;
}, [period]);
return ( return (
<div className={cn('', className)} {...props}> <div className={cn('', className)} {...props}>
<div className="flex items-center justify-center gap-x-6"> <div className="flex items-center justify-center gap-x-6">
@@ -76,40 +86,40 @@ export const PricingTable = ({ className, ...props }: PricingTableProps) => {
<div className="mt-12 grid grid-cols-1 gap-x-6 gap-y-12 md:grid-cols-2 lg:grid-cols-3"> <div className="mt-12 grid grid-cols-1 gap-x-6 gap-y-12 md:grid-cols-2 lg:grid-cols-3">
<div <div
data-plan="free" data-plan="self-hosted"
className="bg-background shadow-foreground/5 flex flex-col items-center justify-center rounded-lg border px-8 py-12 shadow-lg" className="bg-background shadow-foreground/5 flex flex-col items-center justify-center rounded-lg border px-8 py-12 shadow-lg"
> >
<p className="text-foreground text-4xl font-medium">Free Plan</p> <p className="text-foreground text-4xl font-medium">Self Hosted</p>
<p className="text-primary mt-2.5 text-xl font-medium">$0</p> <p className="text-primary mt-2.5 text-xl font-medium">Free</p>
<p className="text-foreground mt-4 max-w-[30ch] text-center"> <p className="text-foreground mt-4 max-w-[30ch] text-center">
For small teams and individuals with basic needs. For small teams and individuals who need a simple solution
</p> </p>
<Button className="rounded-full text-base" asChild>
<Link <Link
href={`${process.env.NEXT_PUBLIC_WEBAPP_URL}/signup`} href="https://github.com/documenso/documenso"
target="_blank" target="_blank"
className="mt-6" className="mt-6"
onClick={() => event('view-github')}
> >
Signup Now <Button className="rounded-full text-base">View on Github</Button>
</Link> </Link>
</Button>
<div className="mt-8 flex w-full flex-col divide-y"> <div className="mt-8 flex w-full flex-col divide-y">
<p className="text-foreground py-4">5 standard documents per month</p> <p className="text-foreground py-4 font-medium">Host your own instance</p>
<p className="text-foreground py-4">Up to 10 recipients per document</p> <p className="text-foreground py-4">Full Control</p>
<p className="text-foreground py-4">No credit card required</p> <p className="text-foreground py-4">Customizability</p>
<p className="text-foreground py-4">Docker Ready</p>
<p className="text-foreground py-4">Community Support</p>
<p className="text-foreground py-4">Free, Forever</p>
</div> </div>
<div className="flex-1" />
</div> </div>
<div <div
data-plan="community" data-plan="community"
className="border-primary bg-background shadow-foreground/5 flex flex-col items-center justify-center rounded-lg border-2 px-8 py-12 shadow-[0px_0px_0px_4px_#E3E3E380]" className="border-primary bg-background shadow-foreground/5 flex flex-col items-center justify-center rounded-lg border-2 px-8 py-12 shadow-[0px_0px_0px_4px_#E3E3E380]"
> >
<p className="text-foreground text-4xl font-medium">Early Adopters</p> <p className="text-foreground text-4xl font-medium">Community</p>
<div className="text-primary mt-2.5 text-xl font-medium"> <div className="text-primary mt-2.5 text-xl font-medium">
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
{period === 'MONTHLY' && <motion.div layoutId="pricing">$30</motion.div>} {period === 'MONTHLY' && <motion.div layoutId="pricing">$30</motion.div>}
@@ -121,27 +131,17 @@ export const PricingTable = ({ className, ...props }: PricingTableProps) => {
For fast-growing companies that aim to scale across multiple teams. For fast-growing companies that aim to scale across multiple teams.
</p> </p>
<Button className="mt-6 rounded-full text-base" asChild> <ClaimPlanDialog planId={planId}>
<Link href={`${process.env.NEXT_PUBLIC_WEBAPP_URL}/signup`}>Signup Now</Link> <Button className="mt-6 rounded-full text-base">Signup Now</Button>
</Button> </ClaimPlanDialog>
<div className="mt-8 flex w-full flex-col divide-y"> <div className="mt-8 flex w-full flex-col divide-y">
<p className="text-foreground py-4 font-medium"> <p className="text-foreground py-4 font-medium">Documenso Early Adopter Deal:</p>
{' '}
<a href="https://documenso.com/blog/early-adopters" target="_blank">
The Early Adopter Deal:
</a>
</p>
<p className="text-foreground py-4">Join the movement</p> <p className="text-foreground py-4">Join the movement</p>
<p className="text-foreground py-4">Simple signing solution</p> <p className="text-foreground py-4">Simple signing solution</p>
<p className="text-foreground py-4">Email, Discord and Slack assistance</p> <p className="text-foreground py-4">Email and Slack assistance</p>
<p className="text-foreground py-4"> <p className="text-foreground py-4">
<strong> <strong>Includes all upcoming features</strong>
{' '}
<a href="https://documenso.com/blog/early-adopters" target="_blank">
Includes all upcoming features
</a>
</strong>
</p> </p>
<p className="text-foreground py-4">Fixed, straightforward pricing</p> <p className="text-foreground py-4">Fixed, straightforward pricing</p>
</div> </div>
@@ -168,7 +168,7 @@ export const PricingTable = ({ className, ...props }: PricingTableProps) => {
</Link> </Link>
<div className="mt-8 flex w-full flex-col divide-y"> <div className="mt-8 flex w-full flex-col divide-y">
<p className="text-foreground py-4 font-medium">Everything in Early Adopters, plus:</p> <p className="text-foreground py-4 font-medium">Everything in Community, plus:</p>
<p className="text-foreground py-4">Custom Subdomain</p> <p className="text-foreground py-4">Custom Subdomain</p>
<p className="text-foreground py-4">Compliance Check</p> <p className="text-foreground py-4">Compliance Check</p>
<p className="text-foreground py-4">Guaranteed Uptime</p> <p className="text-foreground py-4">Guaranteed Uptime</p>

View File

@@ -2,14 +2,15 @@ import { HTMLAttributes } from 'react';
import Image from 'next/image'; import Image from 'next/image';
import backgroundPattern from '@documenso/assets/images/background-pattern.png';
import cardConnectionsFigure from '@documenso/assets/images/card-connections-figure.png';
import cardPaidFigure from '@documenso/assets/images/card-paid-figure.png';
import cardSharingFigure from '@documenso/assets/images/card-sharing-figure.png';
import cardWidgetFigure from '@documenso/assets/images/card-widget-figure.png';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Card, CardContent } from '@documenso/ui/primitives/card'; import { Card, CardContent } from '@documenso/ui/primitives/card';
import backgroundPattern from '~/assets/background-pattern.png';
import cardConnectionsFigure from '~/assets/card-connections-figure.png';
import cardPaidFigure from '~/assets/card-paid-figure.png';
import cardSharingFigure from '~/assets/card-sharing-figure.png';
import cardWidgetFigure from '~/assets/card-widget-figure.png';
export type ShareConnectPaidWidgetBentoProps = HTMLAttributes<HTMLDivElement>; export type ShareConnectPaidWidgetBentoProps = HTMLAttributes<HTMLDivElement>;
export const ShareConnectPaidWidgetBento = ({ export const ShareConnectPaidWidgetBento = ({

View File

@@ -0,0 +1,234 @@
'use server';
import { createElement } from 'react';
import { DateTime } from 'luxon';
import { PDFDocument } from 'pdf-lib';
import { match } from 'ts-pattern';
import { z } from 'zod';
import { mailer } from '@documenso/email/mailer';
import { render } from '@documenso/email/render';
import { DocumentSelfSignedEmailTemplate } from '@documenso/email/templates/document-self-signed';
import { FROM_ADDRESS, FROM_NAME, SERVICE_USER_EMAIL } from '@documenso/lib/constants/email';
import { insertFieldInPDF } from '@documenso/lib/server-only/pdf/insert-field-in-pdf';
import { alphaid } from '@documenso/lib/universal/id';
import { getFile } from '@documenso/lib/universal/upload/get-file';
import { prisma } from '@documenso/prisma';
import {
DocumentDataType,
DocumentStatus,
FieldType,
Prisma,
ReadStatus,
SendStatus,
SigningStatus,
} from '@documenso/prisma/client';
const ZCreateSinglePlayerDocumentSchema = z.object({
documentData: z.object({
data: z.string(),
type: z.nativeEnum(DocumentDataType),
}),
documentName: z.string(),
signer: z.object({
email: z.string().email().min(1),
name: z.string(),
signature: z.string(),
}),
fields: z.array(
z.object({
page: z.number(),
type: z.nativeEnum(FieldType),
positionX: z.number(),
positionY: z.number(),
width: z.number(),
height: z.number(),
}),
),
});
export type TCreateSinglePlayerDocumentSchema = z.infer<typeof ZCreateSinglePlayerDocumentSchema>;
/**
* Create and self signs a document.
*
* Returns the document token.
*/
export const createSinglePlayerDocument = async (
value: TCreateSinglePlayerDocumentSchema,
): Promise<string> => {
const { signer, fields, documentData, documentName } =
ZCreateSinglePlayerDocumentSchema.parse(value);
const document = await getFile({
data: documentData.data,
type: documentData.type,
});
const doc = await PDFDocument.load(document);
const createdAt = new Date();
const isBase64 = signer.signature.startsWith('data:image/png;base64,');
const signatureImageAsBase64 = isBase64 ? signer.signature : null;
const typedSignature = !isBase64 ? signer.signature : null;
// Update the document with the fields inserted.
for (const field of fields) {
const isSignatureField = field.type === FieldType.SIGNATURE;
await insertFieldInPDF(doc, {
...mapField(field, signer),
Signature: isSignatureField
? {
created: createdAt,
signatureImageAsBase64,
typedSignature,
// Dummy data.
id: -1,
recipientId: -1,
fieldId: -1,
}
: null,
// Dummy data.
id: -1,
documentId: -1,
recipientId: -1,
});
}
const pdfBytes = await doc.save();
const documentToken = await prisma.$transaction(
async (tx) => {
const documentToken = alphaid();
// Fetch service user who will be the owner of the document.
const serviceUser = await tx.user.findFirstOrThrow({
where: {
email: SERVICE_USER_EMAIL,
},
});
const documentDataBytes = Buffer.from(pdfBytes).toString('base64');
const { id: documentDataId } = await tx.documentData.create({
data: {
type: DocumentDataType.BYTES_64,
data: documentDataBytes,
initialData: documentDataBytes,
},
});
// Create document.
const document = await tx.document.create({
data: {
title: documentName,
status: DocumentStatus.COMPLETED,
documentDataId,
userId: serviceUser.id,
createdAt,
},
});
// Create recipient.
const recipient = await tx.recipient.create({
data: {
documentId: document.id,
name: signer.name,
email: signer.email,
token: documentToken,
signedAt: createdAt,
readStatus: ReadStatus.OPENED,
signingStatus: SigningStatus.SIGNED,
sendStatus: SendStatus.SENT,
},
});
// Create fields and signatures.
await Promise.all(
fields.map(async (field) => {
const insertedField = await tx.field.create({
data: {
documentId: document.id,
recipientId: recipient.id,
...mapField(field, signer),
},
});
if (field.type === FieldType.SIGNATURE || field.type === FieldType.FREE_SIGNATURE) {
await tx.signature.create({
data: {
fieldId: insertedField.id,
signatureImageAsBase64,
typedSignature,
recipientId: recipient.id,
},
});
}
}),
);
return documentToken;
},
{
maxWait: 5000,
timeout: 30000,
},
);
// Todo: Handle `downloadLink`
const template = createElement(DocumentSelfSignedEmailTemplate, {
downloadLink: `${process.env.NEXT_PUBLIC_MARKETING_URL}/single-player-mode/${documentToken}`,
documentName: documentName,
assetBaseUrl: process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000',
});
// Send email to signer.
await mailer.sendMail({
to: {
address: signer.email,
name: signer.name,
},
from: {
name: FROM_NAME,
address: FROM_ADDRESS,
},
subject: 'Document signed',
html: render(template),
text: render(template, { plainText: true }),
});
return documentToken;
};
/**
* Map the fields provided by the user to fields compatible with Prisma.
*
* Signature fields are handled separately.
*
* @param field The field passed in by the user.
* @param signer The details of the person who is signing this document.
* @returns A field compatible with Prisma.
*/
const mapField = (
field: TCreateSinglePlayerDocumentSchema['fields'][number],
signer: TCreateSinglePlayerDocumentSchema['signer'],
) => {
const customText = match(field.type)
.with(FieldType.DATE, () => DateTime.now().toFormat('yyyy-MM-dd hh:mm a'))
.with(FieldType.EMAIL, () => signer.email)
.with(FieldType.NAME, () => signer.name)
.otherwise(() => '');
return {
type: field.type,
page: field.page,
positionX: new Prisma.Decimal(field.positionX),
positionY: new Prisma.Decimal(field.positionY),
width: new Prisma.Decimal(field.width),
height: new Prisma.Decimal(field.height),
customText,
inserted: true,
};
};

View File

@@ -4,37 +4,64 @@ import { useEffect, useState } from 'react';
import Link from 'next/link'; import Link from 'next/link';
import signingCelebration from '@documenso/assets/images/signing-celebration.png'; import { Share } from 'lucide-react';
import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag'; import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag';
import { DocumentStatus, Signature } from '@documenso/prisma/client'; 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 { DocumentWithRecipient } from '@documenso/prisma/types/document-with-recipient';
import DocumentDialog from '@documenso/ui/components/document/document-dialog'; import DocumentDialog from '@documenso/ui/components/document/document-dialog';
import { DocumentDownloadButton } from '@documenso/ui/components/document/document-download-button'; 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 { SigningCard3D } from '@documenso/ui/components/signing-card';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button'; import { Button } from '@documenso/ui/primitives/button';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { ConfettiScreen } from '~/components/(marketing)/confetti-screen'; import signingCelebration from '~/assets/signing-celebration.png';
import ConfettiScreen from '~/components/(marketing)/confetti-screen';
import { DocumentStatus } from '.prisma/client';
interface SinglePlayerModeSuccessProps { interface SinglePlayerModeSuccessProps {
className?: string; className?: string;
document: DocumentWithRecipient; document: DocumentWithRecipient;
signatures: Signature[];
} }
export const SinglePlayerModeSuccess = ({ export const SinglePlayerModeSuccess = ({ className, document }: SinglePlayerModeSuccessProps) => {
className,
document,
signatures,
}: SinglePlayerModeSuccessProps) => {
const { getFlag } = useFeatureFlags(); const { getFlag } = useFeatureFlags();
const isConfettiEnabled = getFlag('marketing_spm_confetti'); const isConfettiEnabled = getFlag('marketing_spm_confetti');
const [showDocumentDialog, setShowDocumentDialog] = useState(false); const [showDocumentDialog, setShowDocumentDialog] = useState(false);
const [isFetchingDocumentFile, setIsFetchingDocumentFile] = useState(false);
const [documentFile, setDocumentFile] = useState<string | null>(null);
const { documentData } = document; const { toast } = useToast();
const onShowDocumentClick = async () => {
if (isFetchingDocumentFile) {
return;
}
setIsFetchingDocumentFile(true);
try {
const data = await getFile(document.documentData);
setDocumentFile(base64.encode(data));
setShowDocumentDialog(true);
} catch {
toast({
title: 'Something went wrong.',
description: 'We were unable to retrieve the document at this time. Please try again.',
variant: 'destructive',
duration: 7500,
});
}
setIsFetchingDocumentFile(false);
};
useEffect(() => { useEffect(() => {
window.scrollTo({ top: 0 }); window.scrollTo({ top: 0 });
@@ -54,18 +81,17 @@ export const SinglePlayerModeSuccess = ({
<SigningCard3D <SigningCard3D
className="mt-8" className="mt-8"
name={document.Recipient.name || document.Recipient.email} name={document.Recipient.name || document.Recipient.email}
signature={signatures.at(0)}
signingCelebrationImage={signingCelebration} signingCelebrationImage={signingCelebration}
/> />
<div className="relative mt-8 w-full"> <div className="relative mt-8 w-full">
<div className={cn('flex flex-col items-center', className)}> <div className={cn('flex flex-col items-center', className)}>
<div className="grid w-full max-w-sm grid-cols-2 gap-4"> <div className="grid w-full max-w-sm grid-cols-2 gap-4">
<DocumentShareButton {/* TODO: Hook this up */}
documentId={document.id} <Button variant="outline" className="flex-1 bg-transparent backdrop-blur-sm" disabled>
token={document.Recipient.token} <Share className="mr-2 h-5 w-5" />
className="flex-1 bg-transparent backdrop-blur-sm" Share
/> </Button>
<DocumentDownloadButton <DocumentDownloadButton
className="flex-1 bg-transparent backdrop-blur-sm" className="flex-1 bg-transparent backdrop-blur-sm"
@@ -74,7 +100,11 @@ export const SinglePlayerModeSuccess = ({
disabled={document.status !== DocumentStatus.COMPLETED} disabled={document.status !== DocumentStatus.COMPLETED}
/> />
<Button onClick={() => setShowDocumentDialog(true)} className="z-10 col-span-2"> <Button
onClick={async () => onShowDocumentClick()}
loading={isFetchingDocumentFile}
className="col-span-2"
>
Show document Show document
</Button> </Button>
</div> </div>
@@ -94,7 +124,7 @@ export const SinglePlayerModeSuccess = ({
</p> </p>
<DocumentDialog <DocumentDialog
documentData={documentData} document={documentFile ?? ''}
open={showDocumentDialog} open={showDocumentDialog}
onOpenChange={setShowDocumentDialog} onOpenChange={setShowDocumentDialog}
/> />

View File

@@ -31,7 +31,7 @@ import { FormErrorMessage } from '../form/form-error-message';
const ZWidgetFormSchema = z const ZWidgetFormSchema = z
.object({ .object({
email: z.string().email({ message: 'Please enter a valid email address.' }), email: z.string().email({ message: 'Please enter a valid email address.' }),
name: z.string().trim().min(3, { message: 'Please enter a valid name.' }), name: z.string().min(3, { message: 'Please enter a valid name.' }),
}) })
.and( .and(
z.union([ z.union([
@@ -41,7 +41,7 @@ const ZWidgetFormSchema = z
}), }),
z.object({ z.object({
signatureDataUrl: z.null().or(z.string().max(0)), signatureDataUrl: z.null().or(z.string().max(0)),
signatureText: z.string().trim().min(1), signatureText: z.string().min(1),
}), }),
]), ]),
); );
@@ -189,7 +189,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
className="bg-foreground/5 col-span-12 flex flex-col rounded-2xl p-6 lg:col-span-5" className="bg-foreground/5 col-span-12 flex flex-col rounded-2xl p-6 lg:col-span-5"
onSubmit={handleSubmit(onFormSubmit)} onSubmit={handleSubmit(onFormSubmit)}
> >
<h3 className="text-2xl font-semibold">Sign up for the early adopters plan</h3> <h3 className="text-2xl font-semibold">Sign up for the community plan</h3>
<p className="text-muted-foreground mt-2 text-xs"> <p className="text-muted-foreground mt-2 text-xs">
with Timur Ercan & Lucas Smith from Documenso with Timur Ercan & Lucas Smith from Documenso
</p> </p>
@@ -226,7 +226,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
type="button" type="button"
className="bg-primary h-full w-14 rounded" className="bg-primary h-full w-14 rounded"
disabled={!field.value || !!errors.email?.message} disabled={!field.value || !!errors.email?.message}
onClick={() => step === 'EMAIL' && onNextStepClick()} onClick={() => onNextStepClick()}
> >
Next Next
</Button> </Button>
@@ -303,10 +303,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
<div className="mt-12 flex-1" /> <div className="mt-12 flex-1" />
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className="text-muted-foreground text-xs"> <p className="text-muted-foreground text-xs">{stepsRemaining} step(s) until signed</p>
{isValid ? 'Ready for Signing' : `${stepsRemaining} step(s) until signed`}
</p>
<p className="text-muted-foreground block text-xs md:hidden">Minimise contract</p> <p className="text-muted-foreground block text-xs md:hidden">Minimise contract</p>
</div> </div>
@@ -316,7 +313,6 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
'w-1/3': stepsRemaining === 3, 'w-1/3': stepsRemaining === 3,
'w-2/3': stepsRemaining === 2, 'w-2/3': stepsRemaining === 2,
'w-11/12': stepsRemaining === 1, 'w-11/12': stepsRemaining === 1,
'w-full': isValid,
})} })}
/> />
</div> </div>
@@ -381,7 +377,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
</Card> </Card>
<Dialog open={showSigningDialog} onOpenChange={setShowSigningDialog}> <Dialog open={showSigningDialog} onOpenChange={setShowSigningDialog}>
<DialogContent position="center"> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle>Add your signature</DialogTitle> <DialogTitle>Add your signature</DialogTitle>
</DialogHeader> </DialogHeader>
@@ -395,7 +391,6 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
<SignaturePad <SignaturePad
className="aspect-video w-full rounded-md border" className="aspect-video w-full rounded-md border"
defaultValue={signatureDataUrl || ''}
onChange={setDraftSignatureDataUrl} onChange={setDraftSignatureDataUrl}
/> />

View File

@@ -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];
}

View File

@@ -2,7 +2,7 @@ import { NextApiRequest, NextApiResponse } from 'next';
import { randomUUID } from 'crypto'; import { randomUUID } from 'crypto';
import { TEarlyAdopterCheckoutMetadataSchema } from '@documenso/ee/server-only/stripe/webhook/early-adopter-checkout-metadata'; import { hashSync } from '@documenso/lib/server-only/auth/hash';
import { redis } from '@documenso/lib/server-only/redis'; import { redis } from '@documenso/lib/server-only/redis';
import { stripe } from '@documenso/lib/server-only/stripe'; import { stripe } from '@documenso/lib/server-only/stripe';
import { prisma } from '@documenso/prisma'; import { prisma } from '@documenso/prisma';
@@ -36,38 +36,64 @@ export default async function handler(
where: { where: {
email: email.toLowerCase(), email: email.toLowerCase(),
}, },
include: {
Subscription: true,
},
}); });
if (user) { if (user && user.Subscription.length > 0) {
return res.status(200).json({ return res.status(200).json({
redirectUrl: `${process.env.NEXT_PUBLIC_WEBAPP_URL}/signin`, redirectUrl: `${process.env.NEXT_PUBLIC_WEBAPP_URL}/login`,
}); });
} }
const clientReferenceId = randomUUID(); const password = Math.random().toString(36).slice(2, 9);
const passwordHash = hashSync(password);
const { id: userId } = await prisma.user.upsert({
where: {
email: email.toLowerCase(),
},
create: {
email: email.toLowerCase(),
name,
password: passwordHash,
},
update: {
name,
password: passwordHash,
},
});
await redis.set(`user:${userId}:temp-password`, password, {
// expire in 24 hours
ex: 60 * 60 * 24,
});
const signatureDataUrlKey = randomUUID();
if (signatureDataUrl) { if (signatureDataUrl) {
await redis.set(`signature:${clientReferenceId}`, signatureDataUrl, { await redis.set(`signature:${signatureDataUrlKey}`, signatureDataUrl, {
// expire in 7 days // expire in 7 days
ex: 60 * 60 * 24 * 7, ex: 60 * 60 * 24 * 7,
}); });
} }
const metadata: TEarlyAdopterCheckoutMetadataSchema = { const metadata: Record<string, string> = {
name, name,
email, email,
signatureText: signatureText || name, signatureText: signatureText || name,
source: 'marketing', source: 'landing',
}; };
if (signatureDataUrl) { if (signatureDataUrl) {
metadata.signatureDataUrl = clientReferenceId; metadata.signatureDataUrl = signatureDataUrlKey;
} }
const checkout = await stripe.checkout.sessions.create({ const checkout = await stripe.checkout.sessions.create({
customer_email: email, customer_email: email,
// Using the UUID here means our webhook will not try to use it as a user ID. client_reference_id: userId.toString(),
client_reference_id: clientReferenceId, payment_method_types: ['card'],
line_items: [ line_items: [
{ {
price: planId, price: planId,
@@ -78,7 +104,9 @@ export default async function handler(
metadata, metadata,
allow_promotion_codes: true, allow_promotion_codes: true,
success_url: `${process.env.NEXT_PUBLIC_MARKETING_URL}/claimed?sessionId={CHECKOUT_SESSION_ID}`, success_url: `${process.env.NEXT_PUBLIC_MARKETING_URL}/claimed?sessionId={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_MARKETING_URL}`, cancel_url: `${process.env.NEXT_PUBLIC_MARKETING_URL}/pricing?email=${encodeURIComponent(
email,
)}&name=${encodeURIComponent(name)}&planId=${planId}&cancelled=true`,
}); });
if (!checkout.url) { if (!checkout.url) {

View File

@@ -1,6 +1,7 @@
import { NextApiRequest, NextApiResponse } from 'next'; import { NextApiRequest, NextApiResponse } from 'next';
import { randomBytes } from 'crypto'; import { randomBytes } from 'crypto';
import { readFileSync } from 'fs';
import { buffer } from 'micro'; import { buffer } from 'micro';
import { insertImageInPDF } from '@documenso/lib/server-only/pdf/insert-image-in-pdf'; import { insertImageInPDF } from '@documenso/lib/server-only/pdf/insert-image-in-pdf';
@@ -87,11 +88,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const now = new Date(); const now = new Date();
const bytes64 = await fetch( const bytes64 = readFileSync('./public/documenso-supporter-pledge.pdf').toString('base64');
new URL('@documenso/assets/documenso-supporter-pledge.pdf', import.meta.url),
)
.then(async (res) => res.arrayBuffer())
.then((buffer) => Buffer.from(buffer).toString('base64'));
const { id: documentDataId } = await prisma.documentData.create({ const { id: documentDataId } = await prisma.documentData.create({
data: { data: {

View File

@@ -1,12 +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 const config = {
maxDuration: 60,
};
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext: async ({ req, res }) => createTrpcContext({ req, res }),
});

View File

@@ -18,7 +18,6 @@
}, },
"include": [ "include": [
"next-env.d.ts", "next-env.d.ts",
"**/*.mjs",
"**/*.ts", "**/*.ts",
"**/*.tsx", "**/*.tsx",
".next/types/**/*.ts", ".next/types/**/*.ts",

View File

@@ -1,57 +1,34 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
const path = require('path'); const path = require('path');
const { version } = require('./package.json'); const { version } = require('./package.json');
const ENV_FILES = ['.env', '.env.local', `.env.${process.env.NODE_ENV || 'development'}`]; require('dotenv').config({
path: path.join(__dirname, '../../.env.local'),
ENV_FILES.forEach((file) => {
require('dotenv').config({
path: path.join(__dirname, `../../${file}`),
});
}); });
// !: This is a temp hack to get caveat working without placing it back in the public directory.
// !: By inlining this at build time we should be able to sign faster.
const FONT_CAVEAT_BYTES = fs.readFileSync(
path.join(__dirname, '../../packages/assets/fonts/caveat.ttf'),
);
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const config = { const config = {
output: process.env.DOCKER_OUTPUT ? 'standalone' : undefined,
experimental: { experimental: {
outputFileTracingRoot: path.join(__dirname, '../../'), serverActions: true,
serverActionsBodySizeLimit: '50mb', serverActionsBodySizeLimit: '50mb',
}, },
reactStrictMode: true, reactStrictMode: true,
transpilePackages: [ transpilePackages: [
'@documenso/assets',
'@documenso/ee',
'@documenso/lib', '@documenso/lib',
'@documenso/prisma', '@documenso/prisma',
'@documenso/tailwind-config',
'@documenso/trpc', '@documenso/trpc',
'@documenso/ui', '@documenso/ui',
'@documenso/email',
], ],
env: { env: {
APP_VERSION: version, APP_VERSION: version,
NEXT_PUBLIC_PROJECT: 'web', NEXT_PUBLIC_PROJECT: 'web',
FONT_CAVEAT_URI: `data:font/ttf;base64,${FONT_CAVEAT_BYTES.toString('base64')}`,
}, },
modularizeImports: { modularizeImports: {
'lucide-react': { 'lucide-react': {
transform: 'lucide-react/dist/esm/icons/{{ kebabCase member }}', transform: 'lucide-react/dist/esm/icons/{{ kebabCase member }}',
}, },
}, },
webpack: (config, { isServer }) => {
// fixes: Module not found: Cant resolve ../build/Release/canvas.node
if (isServer) {
config.resolve.alias.canvas = false;
}
return config;
},
async rewrites() { async rewrites() {
return [ return [
{ {
@@ -60,32 +37,6 @@ const config = {
}, },
]; ];
}, },
async redirects() {
return [
{
permanent: true,
source: '/documents/:id/sign',
destination: '/sign/:token',
has: [
{
type: 'query',
key: 'token',
},
],
},
{
permanent: true,
source: '/documents/:id/signed',
destination: '/sign/:token',
has: [
{
type: 'query',
key: 'token',
},
],
},
];
},
}; };
module.exports = config; module.exports = config;

View File

@@ -8,12 +8,10 @@
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"lint:fix": "next lint --fix",
"clean": "rimraf .next && rimraf node_modules", "clean": "rimraf .next && rimraf node_modules",
"copy:pdfjs": "node ../../scripts/copy-pdfjs.cjs" "copy:pdfjs": "node ../../scripts/copy-pdfjs.cjs"
}, },
"dependencies": { "dependencies": {
"@documenso/assets": "*",
"@documenso/ee": "*", "@documenso/ee": "*",
"@documenso/lib": "*", "@documenso/lib": "*",
"@documenso/prisma": "*", "@documenso/prisma": "*",
@@ -27,8 +25,8 @@
"lucide-react": "^0.279.0", "lucide-react": "^0.279.0",
"luxon": "^3.4.0", "luxon": "^3.4.0",
"micro": "^10.0.1", "micro": "^10.0.1",
"next": "14.0.0", "next": "13.4.19",
"next-auth": "4.24.3", "next-auth": "4.22.3",
"next-plausible": "^3.10.1", "next-plausible": "^3.10.1",
"next-themes": "^0.2.1", "next-themes": "^0.2.1",
"perfect-freehand": "^1.2.0", "perfect-freehand": "^1.2.0",
@@ -38,13 +36,12 @@
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-dropzone": "^14.2.3", "react-dropzone": "^14.2.3",
"react-hook-form": "^7.43.9", "react-hook-form": "^7.43.9",
"react-hotkeys-hook": "^4.4.1", "react-icons": "^4.8.0",
"react-icons": "^4.11.0",
"react-rnd": "^10.4.1", "react-rnd": "^10.4.1",
"sharp": "0.32.5", "sharp": "0.32.5",
"ts-pattern": "^5.0.5", "ts-pattern": "^5.0.5",
"typescript": "5.2.2", "typescript": "5.1.6",
"zod": "^3.22.4" "zod": "^3.21.4"
}, },
"devDependencies": { "devDependencies": {
"@types/formidable": "^2.0.6", "@types/formidable": "^2.0.6",

View File

@@ -7,7 +7,6 @@ declare namespace NodeJS {
NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID: string; NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID: string;
NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID: string; NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID: string;
NEXT_PUBLIC_STRIPE_FREE_PLAN_ID?: string;
NEXT_PRIVATE_STRIPE_API_KEY: string; NEXT_PRIVATE_STRIPE_API_KEY: string;
NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET: string; NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET: string;

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More