Compare commits

...

384 Commits

Author SHA1 Message Date
48a0f90597 chore(release): 3.5.1 2022-07-30 13:01:00 +02:00
05d3f1f06f fix(server): don't initialize sendgrid if the apikey is empty 2022-07-30 12:57:35 +02:00
4d43f6a642 feat(client): ask for confirmation when resetting a resume 2022-07-30 12:56:40 +02:00
f7363ccdd7 Merge branch 'main' of github.com:AmruthPillai/Reactive-Resume 2022-07-30 12:56:13 +02:00
07c91e9ac2 feat(docker): remove ports from postgres docker instance 2022-07-30 12:56:04 +02:00
cbe08f1d2c Merge pull request #950 from AmruthPillai/dependabot/github_actions/docker/build-push-action-3.1.0
chore(deps): bump docker/build-push-action from 3.0.0 to 3.1.0
2022-07-30 12:43:46 +02:00
c2617a8277 Merge pull request #944 from AmruthPillai/i18n_main
New Crowdin updates
2022-07-30 12:43:36 +02:00
fe72d2de41 chore(release): 3.5.0 2022-07-30 12:42:31 +02:00
23667e218f chore(deps): updating project dependencies to their latest versions 2022-07-30 12:41:37 +02:00
977fa72dde fix(client): 🐛 fix mui rendering of utc dates 2022-07-30 12:21:05 +02:00
5197f954c0 fix(client): 🐛 attempt to fix the one-off date issue
use utc functions from dayjs to correspond to the same date on the server
2022-07-31 02:13:08 -08:00
58341e4cd2 New translations builder.json (Serbian (Cyrillic)) 2022-07-28 13:44:38 +02:00
1559703567 chore(deps): bump docker/build-push-action from 3.0.0 to 3.1.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3.0.0...v3.1.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-25 02:24:03 +00:00
0a1fd50d07 New translations dashboard.json (Norwegian) 2022-07-17 03:00:38 +02:00
1c19062c63 chore(release): 3.4.8 2022-07-13 11:08:14 +02:00
25cf594eb9 feat(google): add toast to display error message from google 2022-07-13 11:05:27 +02:00
1c3beee6cd chore(deps): update dependencies 2022-07-13 09:40:29 +02:00
95c3d4c315 Merge pull request #937 from AmruthPillai/dependabot/gradle/app/org.jetbrains.kotlin.android-1.7.10
chore(deps): bump org.jetbrains.kotlin.android from 1.7.0 to 1.7.10 in /app
2022-07-12 15:33:31 +02:00
85df339e56 chore(deps): bump org.jetbrains.kotlin.android in /app
Bumps [org.jetbrains.kotlin.android](https://github.com/JetBrains/kotlin) from 1.7.0 to 1.7.10.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.7.10/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.7.0...v1.7.10)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin.android
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-11 02:40:56 +00:00
d61ad44ebc chore(release): 3.4.7 2022-07-01 01:04:52 +02:00
ccb1eff749 chore(mui): migrate from mui/lab to mui/x-date-pickers 2022-07-01 01:04:03 +02:00
bfb48e3aa7 fix(mui): update mui datepickers to newer package 2022-07-01 01:01:27 +02:00
e2e08ad390 Merge branch 'main' of github.com:AmruthPillai/Reactive-Resume 2022-07-01 00:50:17 +02:00
f0dda06af3 Merge pull request #932 from AmruthPillai/i18n_main
New Crowdin updates
2022-07-01 00:50:10 +02:00
4c4e77e21d New translations common.json (Portuguese) 2022-07-01 00:48:52 +02:00
f364ae8929 New translations common.json (Indonesian) 2022-07-01 00:48:49 +02:00
b52f292d89 New translations dashboard.json (Indonesian) 2022-07-01 00:48:32 +02:00
8cac7f907c New translations modals.json (Hebrew) 2022-07-01 00:48:25 +02:00
a18a60679f New translations builder.json (Hebrew) 2022-07-01 00:48:04 +02:00
5cc6a81b8c New translations landing.json (Hebrew) 2022-07-01 00:48:02 +02:00
6ff212b698 New translations dashboard.json (Hebrew) 2022-07-01 00:48:00 +02:00
56bcec5196 chore(deps): update dependencies across all projects 2022-07-01 00:46:41 +02:00
12019f90e9 Merge pull request #928 from ravindra3003/main
UpdateTutorial
2022-07-01 00:27:29 +02:00
7e6e69ed49 Update create-resume.mdx 2022-06-23 13:14:16 +05:30
a09a945e17 Update create-account.mdx 2022-06-23 13:12:21 +05:30
df714dc8de Update create-account.mdx 2022-06-22 15:47:01 +05:30
28b63ef0c7 Update create-account.mdx 2022-06-22 15:16:45 +05:30
1b594dac61 Update create-resume.mdx 2022-06-22 15:00:18 +05:30
dd34a30ee0 Update create-account.mdx 2022-06-22 12:09:18 +05:30
0af398ceed Update create-account.mdx 2022-06-22 11:45:45 +05:30
04abd2cacc Update create-account.mdx 2022-06-22 11:37:15 +05:30
a037a091e7 chore(release): 3.4.6 2022-06-19 20:55:23 +02:00
f3a4c17cb4 correct versions 2022-06-19 20:55:14 +02:00
f06f7ad2e5 chore(release): 3.6.2 2022-06-19 20:52:34 +02:00
aab2e5c8a9 correct versions 2022-06-19 20:52:24 +02:00
4318dbe762 add languages 2022-06-19 20:51:10 +02:00
ae3ff274ee updates to app 2022-06-19 20:44:28 +02:00
164403c495 chore(release): 3.4.6 2022-06-19 20:44:04 +02:00
8595c92fb7 Merge pull request #906 from dvd741-a/main
Add File based Storage toggle for Photos
2022-06-18 16:53:05 +02:00
8f75f32f88 Merge pull request #903 from AmruthPillai/i18n_main
New Crowdin updates
2022-06-18 16:52:54 +02:00
0d44189a5f Merge branch 'main' into i18n_main 2022-06-18 16:51:51 +02:00
cd16a6d360 Merge pull request #902 from Mhnramin/main
New translation for Bahasa (Indonesia)
2022-06-18 16:49:25 +02:00
7b795bfaa4 Merge pull request #914 from AmruthPillai/dependabot/gradle/app/org.jetbrains.kotlin.android-1.7.0
chore(deps): bump org.jetbrains.kotlin.android from 1.6.21 to 1.7.0 in /app
2022-06-18 16:49:08 +02:00
8f78d47661 Change Dockerfile to include Volume 2022-06-18 14:21:10 +02:00
0b5e5a2ece New translations common.json (Hebrew) 2022-06-14 03:09:35 +05:30
9eade9514c chore(deps): bump org.jetbrains.kotlin.android in /app
Bumps [org.jetbrains.kotlin.android](https://github.com/JetBrains/kotlin) from 1.6.21 to 1.7.0.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.7.0/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.6.21...v1.7.0)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin.android
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-13 02:22:25 +00:00
d744e06e96 New translations builder.json (Persian) 2022-06-07 23:23:40 +05:30
9657c199d2 New translations common.json (Persian) 2022-06-07 23:23:39 +05:30
2dbe737b73 New translations dashboard.json (Persian) 2022-06-07 23:23:38 +05:30
f624699efa New translations landing.json (Persian) 2022-06-07 23:23:37 +05:30
e46f473754 New translations modals.json (Persian) 2022-06-07 23:23:36 +05:30
767f4bf4bc Correction 2022-06-06 15:41:08 +02:00
1c5d025c15 Version 2022-06-06 15:26:37 +02:00
8de8d89290 File Storage toggle 2022-06-06 15:15:39 +02:00
83662122a5 Changes 2022-06-06 02:31:44 +02:00
126482a760 chore(release): 3.6.1 2022-06-06 01:36:29 +02:00
b04c22a27b Changes 2022-06-06 01:35:46 +02:00
63f88a3d1c Changes 2022-06-06 01:34:58 +02:00
bd519db14f chore(release): 3.6.0 2022-06-06 01:32:56 +02:00
a49aa42176 New translations modals.json (Indonesian) 2022-06-05 12:49:38 +05:30
1a382db4d9 New translations builder.json (Indonesian) 2022-06-05 12:49:36 +05:30
c68f75dc8c New translations common.json (Indonesian) 2022-06-05 12:49:35 +05:30
c12de0c013 New translations dashboard.json (Indonesian) 2022-06-05 12:49:34 +05:30
4cafaf306a New translations landing.json (Indonesian) 2022-06-05 12:49:33 +05:30
0238cf18a5 New translation for Bahasa (Indonesia) 2022-06-05 08:16:49 +08:00
2f6072a7ba Merge pull request #889 from AmruthPillai/i18n_main
New Crowdin updates
2022-05-24 08:25:16 +05:30
55dd2c5925 Merge pull request #879 from AmruthPillai/dependabot/github_actions/docker/build-push-action-3.0.0
chore(deps): bump docker/build-push-action from 2.10.0 to 3.0.0
2022-05-24 08:25:05 +05:30
a3e25f87fa Merge pull request #878 from AmruthPillai/dependabot/github_actions/docker/login-action-2.0.0
chore(deps): bump docker/login-action from 1.14.1 to 2.0.0
2022-05-24 08:24:56 +05:30
9e82ea11c3 chore(release): 3.4.5 2022-05-24 08:23:03 +05:30
62fd63e41f fix(i18n): fix language mismatch in exported pdf 2022-05-24 08:21:03 +05:30
b91c175352 New translations builder.json (Arabic) 2022-05-18 19:51:52 +05:30
898e2314fc New translations builder.json (Arabic) 2022-05-18 18:39:53 +05:30
bca2aa2fe5 chore(deps): bump docker/build-push-action from 2.10.0 to 3.0.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2.10.0 to 3.0.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2.10.0...v3.0.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-09 02:51:05 +00:00
427fdb717a chore(deps): bump docker/login-action from 1.14.1 to 2.0.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 1.14.1 to 2.0.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1.14.1...v2.0.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-09 02:51:02 +00:00
ee5b0187e2 docs(i18n): add Hungarian language to docs readme 2022-05-02 09:01:50 +02:00
94d05f33b4 chore(release): v3.4.4 2022-05-02 08:59:36 +02:00
35fe4e2774 feat(i18n): add Hungrarian (Magyar) language 2022-05-02 08:58:25 +02:00
317901a4d2 Merge pull request #870 from AmruthPillai/i18n_main
New Crowdin updates
2022-05-02 08:50:01 +02:00
350ffcbc43 New translations builder.json (Odia) 2022-05-02 08:47:55 +02:00
2c074a96c8 New translations builder.json (Kannada) 2022-05-02 08:47:54 +02:00
79f140b2d0 New translations builder.json (Malayalam) 2022-05-02 08:47:53 +02:00
649c655ad5 New translations builder.json (Hindi) 2022-05-02 08:47:52 +02:00
d5284a90d1 New translations builder.json (Bengali) 2022-05-02 08:47:51 +02:00
bd18c53ab8 New translations builder.json (Tamil) 2022-05-02 08:47:50 +02:00
704c1ab7d4 New translations builder.json (Vietnamese) 2022-05-02 08:47:35 +02:00
1dbd7f221e New translations builder.json (Chinese Simplified) 2022-05-02 08:47:34 +02:00
e1a47ffbe2 New translations modals.json (Hungarian) 2022-05-02 08:47:33 +02:00
2add629970 New translations modals.json (Czech) 2022-05-02 08:47:31 +02:00
a48fcd9c97 New translations landing.json (Hungarian) 2022-05-02 08:47:29 +02:00
df7b00cb2c New translations builder.json (Turkish) 2022-05-02 08:47:28 +02:00
27fc939101 New translations builder.json (Portuguese) 2022-05-02 08:47:26 +02:00
7c574d17e4 New translations builder.json (Polish) 2022-05-02 08:47:25 +02:00
86a105f5a5 New translations builder.json (Dutch) 2022-05-02 08:47:25 +02:00
327bcc2b32 New translations builder.json (Italian) 2022-05-02 08:47:24 +02:00
a6cbd85010 New translations builder.json (Greek) 2022-05-02 08:47:23 +02:00
371b820923 New translations builder.json (German) 2022-05-02 08:47:22 +02:00
1d47fd0267 New translations builder.json (Danish) 2022-05-02 08:47:21 +02:00
276fc95bb0 New translations builder.json (Czech) 2022-05-02 08:47:20 +02:00
34c8861321 New translations builder.json (Arabic) 2022-05-02 08:47:19 +02:00
780b782579 New translations builder.json (French) 2022-05-02 08:47:18 +02:00
9daa99fd5b New translations builder.json (Spanish) 2022-05-02 08:47:16 +02:00
76b3aa29cf New translations landing.json (Czech) 2022-05-02 08:47:16 +02:00
25d4913fab New translations common.json (Hungarian) 2022-05-02 08:47:15 +02:00
0efeff3a4f New translations common.json (Czech) 2022-05-02 08:47:13 +02:00
f56089925e New translations builder.json (Swedish) 2022-05-02 08:47:12 +02:00
5afae08f20 New translations builder.json (Hungarian) 2022-05-02 08:47:11 +02:00
4bf114dfd6 New translations dashboard.json (Hungarian) 2022-05-02 08:47:09 +02:00
23a3c2e624 New translations dashboard.json (Czech) 2022-05-02 08:47:07 +02:00
71862f4354 New translations builder.json (Russian) 2022-05-01 15:42:24 +02:00
6861c0f0fa chore(release): 3.4.3 2022-05-01 08:03:37 +02:00
9a18e74b90 revert(react): downgrade back to 17.0.2 due to lack of support 2022-05-01 08:03:22 +02:00
4dd1b70079 remove linux/arm64 builds, failing temporarily 2022-04-30 13:39:23 +02:00
f9580fe716 chore(release): 3.4.2 2022-04-30 13:19:34 +02:00
3545f7939f remove linux/arm64 for server, as playwright does not support it 2022-04-30 13:19:08 +02:00
9caad3bc0b chore(release): 3.4.1 2022-04-30 13:01:59 +02:00
5bdb92b1cf fix(typeorm): update typeorm to latest 0.2.x for secpatch 2022-04-30 13:01:45 +02:00
87d381fe8e feat(all): upgrade to v3.4.0 2022-04-30 12:58:17 +02:00
ccfb4d3cb0 Merge pull request #867 from Tomiiwa/Table-of-Contents
[DOC] Added Table of Contents to ReadMe
2022-04-30 09:11:08 +02:00
763074a86c Added Table of Contents to ReadMe 2022-04-29 16:41:52 +01:00
0f46895711 Merge pull request #861 from AmruthPillai/dependabot/github_actions/actions/checkout-3.0.2
chore(deps): bump actions/checkout from 3.0.1 to 3.0.2
2022-04-25 09:34:20 +02:00
aa736af0f5 Merge pull request #858 from AmruthPillai/dependabot/gradle/app/org.jetbrains.kotlin.android-1.6.21
chore(deps): bump org.jetbrains.kotlin.android from 1.6.20 to 1.6.21 in /app
2022-04-25 09:33:53 +02:00
1d9056f935 chore(deps): bump actions/checkout from 3.0.1 to 3.0.2
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3.0.1...v3.0.2)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-25 03:11:03 +00:00
9cadd603f3 chore(deps): bump org.jetbrains.kotlin.android in /app
Bumps org.jetbrains.kotlin.android from 1.6.20 to 1.6.21.

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin.android
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-25 03:08:55 +00:00
b7b62d7bd0 Merge pull request #853 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-24 08:06:24 +02:00
820e6c90d3 New translations modals.json (Greek) 2022-04-22 15:06:52 +02:00
ea642d1b60 New translations landing.json (Greek) 2022-04-22 15:06:51 +02:00
ec006779a8 New translations common.json (Greek) 2022-04-22 15:06:47 +02:00
515be23c44 New translations dashboard.json (Greek) 2022-04-22 15:06:46 +02:00
c11aec8b44 Merge pull request #851 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-22 07:14:41 +02:00
3c2147e72c New translations landing.json (Swedish) 2022-04-21 21:01:56 +02:00
15a35e6243 New translations modals.json (Swedish) 2022-04-21 21:01:53 +02:00
d53a5a492c New translations landing.json (Swedish) 2022-04-21 20:00:31 +02:00
0810e5ae6a Merge pull request #842 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-20 09:21:40 +02:00
881b183db5 Merge pull request #844 from AmruthPillai/dependabot/github_actions/actions/checkout-3.0.1
chore(deps): bump actions/checkout from 3.0.0 to 3.0.1
2022-04-20 09:21:32 +02:00
15cea02872 Delete close-stale.yml 2022-04-19 06:45:45 +02:00
c195561df0 Merge pull request #843 from augustocardoso07/fix/page-counter
Fix page counter in the center section
2022-04-18 18:15:24 +02:00
fc725cfc0c chore(deps): bump actions/checkout from 3.0.0 to 3.0.1
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-18 02:30:45 +00:00
9f54516e8c Fix page counter in the center section 2022-04-17 21:09:55 -03:00
68a4cd9635 New translations builder.json (Swedish) 2022-04-17 19:42:51 +02:00
ff01802f2f New translations common.json (Swedish) 2022-04-17 19:42:49 +02:00
bb900bc2e1 New translations dashboard.json (Swedish) 2022-04-17 19:42:48 +02:00
459f82b66b Merge pull request #828 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-11 07:48:37 +02:00
4b382243e4 New translations modals.json (Odia) 2022-04-10 12:17:28 +02:00
af074085d1 New translations landing.json (Odia) 2022-04-10 12:17:25 +02:00
0c8c872668 New translations dashboard.json (Odia) 2022-04-10 12:17:25 +02:00
ddb29bb40d New translations common.json (Odia) 2022-04-10 12:17:23 +02:00
aecb627ab7 New translations builder.json (Odia) 2022-04-10 12:17:22 +02:00
b8cd53cb59 chore(release): 3.3.4 2022-04-09 22:02:26 +02:00
e61f6153c3 Merge pull request #823 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-09 22:01:54 +02:00
386e8ab902 Merge pull request #827 from AmruthPillai/compose-envs
Remove YAML anchors and prefer Docker Compose Environment Arrays
2022-04-09 22:01:41 +02:00
5e8f02e3ca add local build context comment in docker-compose 2022-04-09 21:47:41 +02:00
f219562e72 style(eslint): client/next: add specific rule for no-html-link-for-pages 2022-04-09 21:25:19 +02:00
29d94dfc14 ci(docker): remove yaml anchors in favor of environment array in docker-compose
fix #825, fix #824, fix #820
2022-04-09 21:21:45 +02:00
622f5fc28c ci(github-actions): update key tags for GitHub action to build docker image 2022-04-09 09:33:44 +02:00
647f01e25c Merge branch 'main' of github.com:AmruthPillai/Reactive-Resume 2022-04-09 09:32:20 +02:00
5a79c0e5c2 chore(release): 3.3.3 2022-04-09 09:32:04 +02:00
2a4c298572 Merge pull request #819 from martadinata666/combine-tags
combine-tags
2022-04-09 09:30:46 +02:00
1e59f73f79 feat(profile): add XING profile icon
fix #821
2022-04-09 09:29:51 +02:00
feb911aea0 feat(s3): implement non-ephemeral storage through S3/DO Spaces 2022-04-09 09:28:08 +02:00
d0863d68c6 chore(release): 3.3.3 2022-04-09 09:26:34 +02:00
447d9b3ca1 New translations builder.json (Greek) 2022-04-08 19:35:17 +02:00
86e66eb6a0 combine-tags 2022-04-08 19:08:01 +07:00
b2c9515a63 Create SECURITY.md 2022-04-08 10:37:24 +02:00
db04c5caee update CHANGELOG.md 2022-04-08 10:34:27 +02:00
33526d5d13 chore(release): 3.3.2 2022-04-08 10:33:44 +02:00
fc77b548d8 fix(types/react): downgrade to <18 2022-04-08 10:33:06 +02:00
bf7a168f2e chore(release): 3.3.1 2022-04-08 09:50:34 +02:00
17b1551bab ci(buildx): buildx docker, remove arm/v7 for non-support 2022-04-08 09:50:23 +02:00
8864243558 update 2022-04-08 09:41:50 +02:00
37aab7a16f chore(release): 3.3.1 2022-04-08 09:40:46 +02:00
86e1bdf7ea chore(typescript): downgrade to "<4.6.0" 2022-04-08 09:40:34 +02:00
4547fd213d chore(release): 3.3.0 2022-04-08 09:39:01 +02:00
5aacec40cc chore(typescript): downgrade to "<4.6.0" 2022-04-08 09:38:41 +02:00
1df78100ca feat(upgrade): changes to code to support new template 2022-04-08 09:37:26 +02:00
9cd36fcb9b Merge pull request #817 from schklom/patch-2
Automatic multi-platform Docker image build
2022-04-08 08:24:17 +02:00
24b32eb917 Merge pull request #811 from klejejs/main
A new template - Leafish
2022-04-08 08:24:10 +02:00
dec0e41fec Merge pull request #806 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-08 08:21:05 +02:00
42700ad2b2 Update docker-build-push.yml
QEMU + Docker Buildx + multi-platform
2022-04-07 18:32:39 +02:00
df51d79f6b Merge pull request #812 from AmruthPillai/dependabot/gradle/app/org.jetbrains.kotlin.android-1.6.20
Bump org.jetbrains.kotlin.android from 1.6.10 to 1.6.20 in /app
2022-04-04 09:57:39 +02:00
be1673a6a7 Bump org.jetbrains.kotlin.android from 1.6.10 to 1.6.20 in /app
Bumps org.jetbrains.kotlin.android from 1.6.10 to 1.6.20.

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin.android
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-04 02:21:29 +00:00
648f182e76 Added new template - Leafish 2022-04-03 20:23:06 +03:00
3aa56f0886 New translations landing.json (Portuguese) 2022-03-31 22:19:33 +02:00
b795534da7 New translations landing.json (Portuguese) 2022-03-31 21:13:27 +02:00
c67e2ac9f8 Merge pull request #791 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-28 16:44:24 +02:00
beb418bd5d chore(release): 3.2.11 2022-03-28 16:43:35 +02:00
2b3d9533b0 Merge pull request #797 from chandiwalaaadhar/fix/#795-No-Scrollbar-on-overflow
Fix-#795 No Scoll Behaviour on Overflow
2022-03-28 16:42:52 +02:00
b061f139bd Fix-#795 No Scoll Behaviour on Overflow 2022-03-28 19:56:54 +05:30
ac569324cf New translations common.json (Portuguese) 2022-03-25 15:24:14 +01:00
357d197bb3 New translations common.json (Portuguese) 2022-03-25 14:13:12 +01:00
5eed1186ff chore(release): 3.2.10 2022-03-24 11:59:03 +01:00
a87a9b3247 revert changes made to unreleased v3.2.10 2022-03-24 11:58:44 +01:00
7f1c82cd91 feat(i18n): add portuguese (pt) language to i18n locales 2022-03-24 11:57:16 +01:00
048c1ed3ed Merge pull request #764 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-24 11:54:48 +01:00
9a2570d7e7 New translations builder.json (Portuguese) 2022-03-24 11:46:44 +01:00
00b9c2156d chore(release): 3.2.10 2022-03-24 11:33:14 +01:00
ff8b22274f ci(docker): use docker compose yaml anchor values and extension fields 2022-03-24 11:32:57 +01:00
786937f847 ci(gh): add .devcontainer for GitHub Codespaces 2022-03-24 09:16:54 +00:00
c95efee8ec perf(security): generate random salt rounds integer 2022-03-24 08:45:22 +01:00
776d2f79a6 ci(dependabot): upgrade npm dependencies manually, using local chore 2022-03-24 08:38:54 +01:00
25a6b8cce6 chore(deps): update dependencies to latest 2022-03-24 08:37:57 +01:00
f6d7cae17b Merge pull request #789 from AmruthPillai/dependabot/npm_and_yarn/typeorm-0.3.3
Bump typeorm from 0.2.45 to 0.3.3
2022-03-24 08:16:39 +01:00
944a0b5fb1 Bump typeorm from 0.2.45 to 0.3.3
Bumps [typeorm](https://github.com/typeorm/typeorm) from 0.2.45 to 0.3.3.
- [Release notes](https://github.com/typeorm/typeorm/releases)
- [Changelog](https://github.com/typeorm/typeorm/blob/master/CHANGELOG.md)
- [Commits](https://github.com/typeorm/typeorm/compare/0.2.45...0.3.3)

---
updated-dependencies:
- dependency-name: typeorm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:15:35 +00:00
7769653224 Merge pull request #782 from AmruthPillai/dependabot/npm_and_yarn/server/nestjs/config-2.0.0
Bump @nestjs/config from 1.2.1 to 2.0.0 in /server
2022-03-24 08:15:25 +01:00
ccdc5b5fae Merge pull request #781 from AmruthPillai/dependabot/npm_and_yarn/docs/types/react-17.0.42
Bump @types/react from 17.0.40 to 17.0.42 in /docs
2022-03-24 08:15:20 +01:00
20158f573e Merge pull request #779 from AmruthPillai/dependabot/npm_and_yarn/client/types/node-17.0.23
Bump @types/node from 17.0.21 to 17.0.23 in /client
2022-03-24 08:15:10 +01:00
87c60729b5 Merge branch 'main' into dependabot/npm_and_yarn/client/types/node-17.0.23 2022-03-24 08:14:59 +01:00
a03a50b7c6 Merge pull request #777 from AmruthPillai/dependabot/npm_and_yarn/server/googleapis-98.0.0
Bump googleapis from 97.0.0 to 98.0.0 in /server
2022-03-24 08:14:35 +01:00
fb85ccf501 Merge pull request #776 from AmruthPillai/dependabot/npm_and_yarn/client/types/react-17.0.42
Bump @types/react from 17.0.40 to 17.0.42 in /client
2022-03-24 08:14:31 +01:00
3179442d8f Merge pull request #773 from AmruthPillai/dependabot/github_actions/docker/build-push-action-2.10.0
Bump docker/build-push-action from 2.9.0 to 2.10.0
2022-03-24 08:14:27 +01:00
33d3c52cd9 Merge pull request #772 from AmruthPillai/dependabot/github_actions/digitalocean/action-doctl-2.1.1
Bump digitalocean/action-doctl from 2.1.0 to 2.1.1
2022-03-24 08:14:22 +01:00
1d33e01a43 Merge pull request #771 from AmruthPillai/dependabot/docker/client/node-17-alpine
Bump node from 16-alpine to 17-alpine in /client
2022-03-24 08:14:17 +01:00
52ff221dd1 Merge pull request #770 from AmruthPillai/dependabot/docker/server/node-17-alpine
Bump node from 16-alpine to 17-alpine in /server
2022-03-24 08:13:57 +01:00
5afe178e23 Update dependabot.yml 2022-03-24 08:13:38 +01:00
9118b76084 Bump @nestjs/config from 1.2.1 to 2.0.0 in /server
Bumps [@nestjs/config](https://github.com/nestjs/config) from 1.2.1 to 2.0.0.
- [Release notes](https://github.com/nestjs/config/releases)
- [Changelog](https://github.com/nestjs/config/blob/master/.release-it.json)
- [Commits](https://github.com/nestjs/config/compare/1.2.1...2.0.0)

---
updated-dependencies:
- dependency-name: "@nestjs/config"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:04:09 +00:00
5a62b527b9 Bump @types/react from 17.0.40 to 17.0.42 in /docs
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 17.0.40 to 17.0.42.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:04:08 +00:00
2e9e14dc72 Bump @types/node from 17.0.21 to 17.0.23 in /client
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 17.0.21 to 17.0.23.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:03:51 +00:00
0a0b4893aa Bump googleapis from 97.0.0 to 98.0.0 in /server
Bumps [googleapis](https://github.com/googleapis/google-api-nodejs-client) from 97.0.0 to 98.0.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/googleapis-v97.0.0...googleapis-v98.0.0)

---
updated-dependencies:
- dependency-name: googleapis
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:03:37 +00:00
6277f81e26 Bump @types/react from 17.0.40 to 17.0.42 in /client
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 17.0.40 to 17.0.42.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:03:35 +00:00
d550150787 Bump docker/build-push-action from 2.9.0 to 2.10.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2.9.0 to 2.10.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2.9.0...v2.10.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:02:41 +00:00
7626b2153f Bump digitalocean/action-doctl from 2.1.0 to 2.1.1
Bumps [digitalocean/action-doctl](https://github.com/digitalocean/action-doctl) from 2.1.0 to 2.1.1.
- [Release notes](https://github.com/digitalocean/action-doctl/releases)
- [Commits](https://github.com/digitalocean/action-doctl/compare/v2.1.0...v2.1.1)

---
updated-dependencies:
- dependency-name: digitalocean/action-doctl
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:02:38 +00:00
6d17d1001d Bump node from 16-alpine to 17-alpine in /client
Bumps node from 16-alpine to 17-alpine.

---
updated-dependencies:
- dependency-name: node
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:02:34 +00:00
0273738d7a Bump node from 16-alpine to 17-alpine in /server
Bumps node from 16-alpine to 17-alpine.

---
updated-dependencies:
- dependency-name: node
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:02:34 +00:00
322df25ecc Merge pull request #769 from modem7/dependabot-changes
Dependabot
2022-03-24 08:02:15 +01:00
ab3867d9a8 Merge pull request #768 from modem7/DockerChanges
Docker changes
2022-03-24 08:01:07 +01:00
9bf8ec88f4 Merge pull request #767 from modem7/readme-update
Update README
2022-03-24 07:58:58 +01:00
685f4d37a6 Merge pull request #766 from modem7/image-size
Reduced image sizes
2022-03-24 07:58:19 +01:00
f3b3fe8ac9 Update dependabot.yml
added gradle
2022-03-24 00:47:21 +00:00
d5fa49172a Create dependabot.yml
This will assist with version updates and vulnerability scans.

Dependabot scans will need to be enabled in the repo itself under https://github.com/AmruthPillai/Reactive-Resume/settings/security_analysis

It would also be worthwhile pairing this with Snyk (https://app.snyk.io/) for vulnerability monitoring.
2022-03-23 23:04:47 +00:00
b8303b9977 Update .env.example
Updated env variables to be clearer about which service requires it.
2022-03-23 23:03:29 +00:00
16d06c6356 Update README.md
As the logo is already in the repo, might as well utilise it.

Added Docker build status
2022-03-23 22:54:33 +00:00
79ddd887d9 Docker changes
Added:
Healthchecks
Changed Postgres to Alpine + pinned
Pinned Traefik Version
Made Env Vars easier to see + change/reference for those using their own env file.
2022-03-23 22:52:30 +00:00
c394bc6725 Reduced image sizes
This reduces images size from a total of 9.22mb to 6.11mb.
2022-03-23 22:41:24 +00:00
9e6d7630f4 New translations landing.json (Portuguese) 2022-03-23 23:06:12 +01:00
e2fbdd3c2f New translations modals.json (Portuguese) 2022-03-23 21:57:14 +01:00
849171af8f New translations dashboard.json (Portuguese) 2022-03-23 21:01:36 +01:00
884975dda6 chore(release): 3.2.9 2022-03-21 08:58:19 +01:00
03cbf22c9b feat(i18n): add nl and ru i18n locales to app 2022-03-21 08:57:47 +01:00
a10cee2efa Merge pull request #740 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-21 08:32:28 +01:00
479c94a11d Merge pull request #746 from GovindKrishnan/main
Cleaned Issue Templates Using Comments
2022-03-21 08:32:18 +01:00
c057f31e97 Merge pull request #750 from chandiwalaaadhar/fix/work-experience-website-link-redirects-404
Fixed URL 404 issue in Profile Section URL
2022-03-21 08:32:08 +01:00
d0bc9db6e5 Fixed issue in Profile Section URL 2022-03-21 06:14:22 +05:30
e2dd8dd1d7 Commenting Out Help Lines [FR Template]
To avoid clutter & increase readability of issues, I suggest commenting out the extra help tips so that they don't appear in the actual report.
2022-03-20 05:48:54 +05:30
f2ff12faa6 Commenting Out Help Lines [Bug Template]
To avoid clutter & increase readability of issues, I suggest commenting out the extra help tips so that they don't appear in the actual report.
2022-03-20 05:45:58 +05:30
50cc3d7da8 New translations modals.json (Russian) 2022-03-19 11:32:35 +01:00
60b1f7a816 New translations dashboard.json (Russian) 2022-03-19 11:32:31 +01:00
33d2bf043b New translations landing.json (Russian) 2022-03-19 10:16:47 +01:00
86b20dcae6 New translations builder.json (Russian) 2022-03-19 10:16:42 +01:00
caf4936c9b New translations dashboard.json (Russian) 2022-03-19 10:16:40 +01:00
7e864d2447 New translations common.json (Russian) 2022-03-19 10:16:38 +01:00
ff324688f6 Merge pull request #742 from GovindKrishnan/main
Linking Badges to Releases & License
2022-03-19 09:29:45 +01:00
efaeb1b341 Linking Badges to Releases & License (DOCS)
Linked the Version badge to Releases and License badge to MIT License.
2022-03-19 09:03:23 +05:30
488cb7f8a2 Linking Badges to Releases & License (README)
Linked the Version badge to Releases and License badge to MIT License.
2022-03-19 08:59:56 +05:30
974fa08651 New translations builder.json (Dutch) 2022-03-18 21:46:54 +01:00
8f3312e8a8 New translations landing.json (Dutch) 2022-03-18 20:46:24 +01:00
57d5da0490 New translations modals.json (Dutch) 2022-03-18 20:46:21 +01:00
daeb67319e New translations dashboard.json (Dutch) 2022-03-18 20:46:18 +01:00
213665bd1d New translations common.json (Dutch) 2022-03-18 20:46:16 +01:00
dfc48d6aa9 Merge pull request #738 from martadinata666/docusaurus-port-server
Update docusaurus to prevent crash with client
2022-03-18 19:38:40 +01:00
d71d40453f Update package.json 2022-03-18 23:23:30 +07:00
635afbc892 Merge pull request #737 from GovindKrishnan/main
Removed Self Referring Link in Docs
2022-03-18 16:47:30 +01:00
e90037e363 Removed Self Referring Link in Docs
Instead, linked to the GitHub Repo so that they can check out this repo.

If you got some other important link, feel free to change.
2022-03-18 20:07:57 +05:30
a730359736 chore(release): 3.2.8 2022-03-18 11:18:10 +01:00
80acfe97c7 fix(disable_user_signups): hide create account link under flag 2022-03-18 11:17:30 +01:00
b6267d07ba feat(flags): introduce flags, disable_user_signups
fix #698
2022-03-18 11:12:26 +01:00
910f764823 Merge pull request #735 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-18 10:56:08 +01:00
7a8f302c21 New translations common.json (Malayalam) 2022-03-18 10:55:35 +01:00
fb0c3b55c1 New translations common.json (Hindi) 2022-03-18 10:55:15 +01:00
f9579855a9 New translations common.json (Bengali) 2022-03-18 10:55:14 +01:00
0dd1e2720a New translations common.json (Vietnamese) 2022-03-18 10:55:14 +01:00
331d2d3d26 New translations common.json (Chinese Simplified) 2022-03-18 10:55:13 +01:00
f56554c2d4 New translations common.json (Turkish) 2022-03-18 10:55:11 +01:00
98131b389c New translations common.json (Portuguese) 2022-03-18 10:55:10 +01:00
7cfe6288e1 New translations common.json (Polish) 2022-03-18 10:55:09 +01:00
84041ef2ff New translations common.json (Italian) 2022-03-18 10:55:07 +01:00
9a2af8079e New translations common.json (German) 2022-03-18 10:54:55 +01:00
633162d9af New translations common.json (Danish) 2022-03-18 10:54:54 +01:00
50baa0227d New translations common.json (Kannada) 2022-03-18 10:54:44 +01:00
18da00f2e2 New translations common.json (Tamil) 2022-03-18 10:54:41 +01:00
f4f0b2c4b5 New translations common.json (Arabic) 2022-03-18 10:54:38 +01:00
b7d3007d31 New translations common.json (Spanish) 2022-03-18 10:54:37 +01:00
67384981c1 New translations common.json (French) 2022-03-18 10:54:36 +01:00
4390bccfb9 feat(i18n): add Vietnamese language to i18n locales 2022-03-18 10:52:06 +01:00
8f5632c5ad feat(client/theme): add theme switcher to landing page 2022-03-18 10:20:39 +01:00
1facd2ad11 fix(client/create-rename-slug): fix slug accepting apostrophes and other special characters
fix #706
2022-03-18 09:37:09 +01:00
0e1e2bbe4e chore(release): 3.2.7 2022-03-18 09:29:54 +01:00
3a2e62be4c feat(i18n): add Malayalam (മലയാളം) language to i18n locales 2022-03-18 09:27:04 +01:00
697ceef8f2 Merge branch 'main' of github.com:AmruthPillai/Reactive-Resume 2022-03-18 09:25:13 +01:00
c8e81a456d Merge pull request #731 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-18 09:25:09 +01:00
2b334e5c5a Merge pull request #727 from chandiwalaaadhar/fix/crash-on-pasting-hex-without-#-prefix
Fix-Crash on Entering Primary Color Hex Code without # Prefix
2022-03-18 09:24:54 +01:00
90321e1284 fix(printer/i18n): fix dates not showing up in resume language when printing
fix #729
2022-03-18 09:24:33 +01:00
9bcddb4b5c New translations modals.json (Malayalam) 2022-03-18 02:48:34 +01:00
72fdc05f69 New translations landing.json (Malayalam) 2022-03-18 02:48:33 +01:00
e1d6540500 New translations dashboard.json (Malayalam) 2022-03-18 02:48:32 +01:00
4b17719c69 New translations common.json (Malayalam) 2022-03-18 02:48:31 +01:00
da056307dd New translations builder.json (Malayalam) 2022-03-18 02:48:29 +01:00
e4950728d8 Refactored- Avoiding modifying the prop 2022-03-18 06:18:17 +05:30
dac4e862b8 Fix-Crash on Entering Primary Color Hex Code without # Prefix 2022-03-17 19:42:26 +05:30
5fa45ef5bd chore(release): 3.2.6 2022-03-17 14:05:31 +01:00
9e6dafc8ca fix(i18n): add missing languages to dayjs date wrapper locales
fix #719
2022-03-17 14:05:13 +01:00
a02b85b4bb fix(linkedin): fix skill modal crashing when importing from linkedin
fix #718
2022-03-17 13:58:49 +01:00
b3ff7805cd fix(json-export): add mimeType and charset to JSON export
fix #726
2022-03-17 13:11:18 +01:00
7f0ee40af4 feat(client/auth/google): disable google login/registration if GOOGLE_CLIENT_ID is not in ENV
fix #724
2022-03-17 12:17:41 +01:00
39fa6da5dd feat(i18n): add arabic language to i18n locale 2022-03-17 12:16:25 +01:00
7fd96a4540 Merge pull request #723 from GovindKrishnan/main
Adding Contributors Wall to README
2022-03-17 07:07:03 +01:00
8f5832b2ca Merge branch 'main' into main 2022-03-17 11:34:46 +05:30
58ce09ee06 Contributors Wall to index.mdx 2022-03-17 11:32:40 +05:30
3f5323d5a3 Update bug-report.md 2022-03-17 07:02:09 +01:00
d62482b280 Merge pull request #722 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-17 06:53:14 +01:00
a609ea551a Merge pull request #720 from chandiwalaaadhar/fix/shared-resume-not-scrollable-on-phone-screen
Fix- Resume Shared is not Scrollable on Phone Screen
2022-03-17 06:52:55 +01:00
1f8e3647d3 Styling 2022-03-16 22:20:58 +05:30
76975ddc6c Adding Contributors Wall to README
Using an open-source web tool called contrib.rocks that sync daily with Contributors Club.

Sort of experimental as I came across this today. But yea, it does no harm to production to say the least. 😅
2022-03-16 22:11:33 +05:30
6ed0bb62b4 New translations modals.json (Arabic) 2022-03-16 17:34:58 +01:00
11d15d8dbb New translations builder.json (Arabic) 2022-03-16 17:34:55 +01:00
7cf92ddb81 New translations dashboard.json (Arabic) 2022-03-16 17:34:53 +01:00
d907b36d59 New translations landing.json (Arabic) 2022-03-16 16:22:21 +01:00
307b626189 Fix- Shared Resume not Scrollable on Phone Screen 2022-03-16 18:45:10 +05:30
f573e60079 Merge pull request #717 from chandiwalaaadhar/fix/integrations-empty-date-sections-not-loading
Fix-Json with Empty Date Strings in Sections doesn't get loaded in the Resume
2022-03-16 11:48:34 +01:00
d3c52476f7 Merge pull request #716 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-16 11:47:00 +01:00
4f9d2ea846 New translations modals.json (Vietnamese) 2022-03-16 09:10:28 +01:00
ec617d682e Revert "Fix- Language Modal Slider Component Label Text Overlapping"
This reverts commit 5a60c99df9.
2022-03-16 13:39:27 +05:30
72d3d46e88 Fix- Integration LinkedIn Empty Date 2022-03-16 13:36:21 +05:30
110797da9d Fix - Integration JSON Resume Empty Date 2022-03-16 13:32:59 +05:30
ab90a2e1dd Fix- Reactive Resume v2 Integration Empty Date 2022-03-16 13:29:37 +05:30
1a3c950847 New translations dashboard.json (Vietnamese) 2022-03-16 08:11:13 +01:00
7fcc792255 New translations landing.json (Vietnamese) 2022-03-16 08:11:10 +01:00
97a13f9f41 New translations builder.json (Vietnamese) 2022-03-16 08:11:08 +01:00
29f1afac9a New translations common.json (Vietnamese) 2022-03-16 08:11:03 +01:00
c5d0abdc79 Merge pull request #714 from chandiwalaaadhar/fix/publication-modal-label-text
Fix- Publication Modal Label text
2022-03-16 07:24:31 +01:00
5a60c99df9 Fix- Language Modal Slider Component Label Text Overlapping 2022-03-16 11:25:48 +05:30
7d188622a8 chore(release): 3.2.5 2022-03-16 06:50:18 +01:00
97e9432d6b feat(i18n): add danish, polish and turkish locales to i18n 2022-03-16 06:48:33 +01:00
c46b8fc162 Fix- Publication Modal Label text 2022-03-16 11:17:33 +05:30
b2f1fb3a55 fix(client/templates): fix text veering off of artboard in most templates
fix #702
2022-03-16 06:41:48 +01:00
4743828e6b chore(deps): update dependencies to match latest patch fixes 2022-03-16 06:40:49 +01:00
519fbbd1b2 Merge pull request #689 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-16 06:21:54 +01:00
ebc084ad52 Create FUNDING.yml 2022-03-16 06:09:50 +01:00
26fdd72610 New translations modals.json (Italian) 2022-03-15 16:28:53 +01:00
ea704c6d99 New translations modals.json (Chinese Simplified) 2022-03-15 16:28:52 +01:00
ea88044d25 New translations modals.json (Bengali) 2022-03-15 16:28:51 +01:00
a461cc147b New translations modals.json (Hindi) 2022-03-15 16:28:50 +01:00
5aefcae2ac New translations modals.json (German) 2022-03-15 16:28:40 +01:00
ba1e968510 New translations modals.json (Spanish) 2022-03-15 16:28:38 +01:00
ba12abe506 New translations modals.json (French) 2022-03-15 16:28:37 +01:00
29fb1dcca3 New translations modals.json (Kannada) 2022-03-15 16:28:14 +01:00
4be6c48aab New translations modals.json (Tamil) 2022-03-15 16:28:13 +01:00
ee1017aa25 Merge pull request #699 from chandiwalaaadhar/fix/pikachu-profile-image-uncontrolled-size
Fix - Pikachu User Image upload, uncontrolled Image Size
2022-03-15 16:25:19 +01:00
bf806c5ecf New translations dashboard.json (Italian) 2022-03-15 15:52:23 +01:00
bf9709ed8e New translations landing.json (Italian) 2022-03-15 15:52:21 +01:00
6c74ecfef7 New translations builder.json (Italian) 2022-03-15 15:52:17 +01:00
fb8c925037 New translations common.json (Italian) 2022-03-15 15:52:13 +01:00
c8c154c2f4 Merge pull request #701 from GovindKrishnan/main
Fixed a Typo in README
2022-03-15 15:15:39 +01:00
92b2c4b757 New translations modals.json (Polish) 2022-03-15 14:41:14 +01:00
260a354c22 New translations dashboard.json (Polish) 2022-03-15 14:41:11 +01:00
c67a969353 New translations landing.json (Polish) 2022-03-15 14:41:09 +01:00
8d61703250 New translations builder.json (Polish) 2022-03-15 14:41:04 +01:00
28df783bba New translations common.json (Polish) 2022-03-15 14:41:03 +01:00
51575a340b New translations modals.json (Danish) 2022-03-15 13:44:39 +01:00
8068d34bf3 New translations dashboard.json (Danish) 2022-03-15 13:44:35 +01:00
b154fae0fa New translations landing.json (Danish) 2022-03-15 13:44:34 +01:00
c5ba1730c3 New translations builder.json (Danish) 2022-03-15 13:44:29 +01:00
a7d90da30e New translations common.json (Danish) 2022-03-15 13:44:26 +01:00
0bbc54a97f Merge pull request #1 from GovindKrishnan/patch-1
Fixed Same Typos in index.mdx
2022-03-15 17:07:47 +05:30
2081f1344f Fixed Same Typos in index.mdx 2022-03-15 17:05:46 +05:30
d029607e16 Fixing Typos in README 2022-03-15 16:46:58 +05:30
5fe0c02cec Fixed a Typo in README
Very trivial. But still, here's my contribution! 😄 

After all, grammar is very important in resumes. 😉
2022-03-15 16:41:10 +05:30
70b45b3686 New translations modals.json (Turkish) 2022-03-15 11:49:35 +01:00
ff098d5df1 New translations landing.json (Turkish) 2022-03-15 11:49:30 +01:00
95d7d70caa New translations builder.json (Turkish) 2022-03-15 10:34:48 +01:00
107ba6e525 New translations common.json (Turkish) 2022-03-15 10:34:45 +01:00
f72e0556e5 Fix - Pikachu User Image after upload covers the center content 2022-03-15 05:57:50 +05:30
7c49b50979 New translations builder.json (Czech) 2022-03-14 21:27:52 +01:00
59b2fc9fd6 New translations common.json (Portuguese) 2022-03-14 18:58:46 +01:00
f93ac987ac New translations dashboard.json (Turkish) 2022-03-14 16:52:59 +01:00
fb32f9b523 New translations common.json (Arabic) 2022-03-14 16:52:52 +01:00
326 changed files with 89355 additions and 5233 deletions

5
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,5 @@
ARG VARIANT="lts-bullseye"
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm

View File

@ -0,0 +1,27 @@
{
"name": "Node.js",
"build": {
"dockerfile": "Dockerfile",
"args": { "VARIANT": "16-bullseye" }
},
// Set *default* container specific settings.json values on container create.
"settings": {},
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "lokalise.i18n-ally"],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [80, 5432],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pnpm install",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node",
"features": {
"docker-from-docker": "latest"
}
}

View File

@ -1,30 +1,33 @@
# App
# Server + Client
TZ=UTC
SECRET_KEY=change-me
PUBLIC_URL=http://localhost:3000
PUBLIC_SERVER_URL=http://localhost:3000/api
PUBLIC_GOOGLE_CLIENT_ID=
# URLs
PUBLIC_URL=http://<SERVER-IP>
PUBLIC_SERVER_URL=http://<SERVER-IP>/api
# Database
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USERNAME=postgres
# Server + Database
POSTGRES_DB=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DATABASE=postgres
# Server
SECRET_KEY=
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_SSL_CERT=
# Auth
JWT_SECRET=change-me
JWT_SECRET=
JWT_EXPIRY_TIME=604800
# Google
PUBLIC_GOOGLE_CLIENT_ID=change-me
GOOGLE_CLIENT_SECRET=change-me
GOOGLE_API_KEY=change-me
# SendGrid (Optional)
GOOGLE_CLIENT_SECRET=
GOOGLE_API_KEY=
SENDGRID_API_KEY=
SENDGRID_FORGOT_PASSWORD_TEMPLATE_ID=
SENDGRID_FROM_NAME=
SENDGRID_FROM_EMAIL=
SENDGRID_FROM_EMAIL=
STORAGE_BUCKET=
STORAGE_REGION=
STORAGE_ENDPOINT=
STORAGE_URL_PREFIX=
STORAGE_ACCESS_KEY=
STORAGE_SECRET_KEY=
# Flags (Client)
PUBLIC_FLAG_DISABLE_SIGNUPS=false

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
custom: https://paypal.me/RajaRajanA

View File

@ -8,31 +8,29 @@ assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
<!-- A clear and concise description of what the bug is. -->
**Product Flavor**
- [ ] Managed (https://rxresu.me)
- [ ] Self Hosted
**To Reproduce**
Steps to reproduce the behavior:
<!-- Steps to reproduce the behavior: -->
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
<!-- A clear and concise description of what you expected to happen. -->
**Screenshots**
If applicable, add screenshots to help explain your problem.
<!-- If applicable, add screenshots to help explain your problem. -->
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
- OS: <!--[e.g. iOS]-->
- Browser <!--[e.g. chrome, safari]-->
- Version <!--[e.g. 22]-->
**Additional context**
Add any other context about the problem here.
<!-- Add any other context about the problem here. -->

View File

@ -8,13 +8,13 @@ assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
Add any other context or screenshots about the feature request here.
<!-- Add any other context or screenshots about the feature request here. -->

22
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,22 @@
version: 2
updates:
- package-ecosystem: 'docker'
directory: '/server'
schedule:
interval: 'weekly'
- package-ecosystem: 'docker'
directory: '/client'
schedule:
interval: 'weekly'
- package-ecosystem: 'gradle'
directory: '/app'
schedule:
interval: 'weekly'
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'

View File

@ -1,16 +0,0 @@
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '0 0 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5.0.0
with:
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity. Remove the stale label or comment on this PR, otherwise it would be closed in 5 days.'
stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity. Remove the stale label or comment on this issue, otherwise it would be closed in 5 days.'
days-before-stale: 30
days-before-close: 5

View File

@ -13,7 +13,7 @@ jobs:
steps:
- name: Install DigitalOcean CLI
uses: digitalocean/action-doctl@v2.1.0
uses: digitalocean/action-doctl@v2.1.1
with:
token: ${{ secrets.DIGITALOCEAN_TOKEN }}

View File

@ -5,26 +5,33 @@ on:
types: [published]
jobs:
docker_client:
name: Docker (Client)
client:
name: Client
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to Docker
uses: docker/login-action@v1.14.1
- name: Login to Docker Hub
uses: docker/login-action@v2.0.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2.0.0
with:
registry: ghcr.io
username: $GITHUB_REPOSITORY_OWNER
password: ${{ secrets.GH_TOKEN }}
- name: Build and Push Client Image
uses: docker/build-push-action@v2.9.0
uses: docker/build-push-action@v3.1.0
with:
context: .
push: true
@ -32,27 +39,36 @@ jobs:
tags: |
amruthpillai/reactive-resume:client-latest
amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
ghcr.io/amruthpillai/reactive-resume:client-latest
ghcr.io/amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
docker_server:
name: Docker (Server)
server:
name: Server
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to Docker
uses: docker/login-action@v1.14.1
- name: Login to Docker Hub
uses: docker/login-action@v2.0.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2.0.0
with:
registry: ghcr.io
username: $GITHUB_REPOSITORY_OWNER
password: ${{ secrets.GH_TOKEN }}
- name: Build and Push Server Image
uses: docker/build-push-action@v2.9.0
uses: docker/build-push-action@v3.1.0
with:
context: .
push: true
@ -60,61 +76,5 @@ jobs:
tags: |
amruthpillai/reactive-resume:server-latest
amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}
github_client:
name: GitHub (Client)
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1.14.1
with:
registry: ghcr.io
username: $GITHUB_REPOSITORY_OWNER
password: ${{ secrets.GH_TOKEN }}
- name: Build and Push Client Image
uses: docker/build-push-action@v2.9.0
with:
context: .
push: true
file: client/Dockerfile
tags: |
ghcr.io/amruthpillai/reactive-resume:client-latest
ghcr.io/amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
github_server:
name: GitHub (Server)
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1.14.1
with:
registry: ghcr.io
username: $GITHUB_REPOSITORY_OWNER
password: ${{ secrets.GH_TOKEN }}
- name: Build and Push Server Image
uses: docker/build-push-action@v2.9.0
with:
context: .
push: true
file: server/Dockerfile
tags: |
ghcr.io/amruthpillai/reactive-resume:server-latest
ghcr.io/amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
auto-install-peers=true
strict-peer-dependencies=false

View File

@ -21,5 +21,10 @@
"i18n-ally.namespace": true,
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
"i18n-ally.sortKeys": true,
"scss.validate": false
"scss.validate": false,
"conventionalCommits.scopes": [
"client",
"server",
"docker"
]
}

View File

@ -2,6 +2,204 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [3.5.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.5.0...v3.5.1) (2022-07-30)
### Features
* **client:** :sparkles: ask for confirmation when resetting a resume ([4d43f6a](https://github.com/AmruthPillai/Reactive-Resume/commit/4d43f6a6427198e62e9fcb995f1a28c0ee4de71e))
* **docker:** :zap: remove ports from postgres docker instance ([07c91e9](https://github.com/AmruthPillai/Reactive-Resume/commit/07c91e9ac21e8ef120d08ab92363d8e48a55aaba))
### Bug Fixes
* **server:** :zap: don't initialize sendgrid if the apikey is empty ([05d3f1f](https://github.com/AmruthPillai/Reactive-Resume/commit/05d3f1f06fbffd899269a5c4dea3c52cf408125f))
## [3.5.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.8...v3.5.0) (2022-07-30)
### Bug Fixes
* **client:** :bug: attempt to fix the one-off date issue ([5197f95](https://github.com/AmruthPillai/Reactive-Resume/commit/5197f954c0baed3daf1c7e2c79b607354ef42024))
* **client:** :bug: fix mui rendering of utc dates ([977fa72](https://github.com/AmruthPillai/Reactive-Resume/commit/977fa72ddeeeebf7463d43a820e85f783489a4dc))
### [3.4.8](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.7...v3.4.8) (2022-07-13)
### Features
* **google:** add toast to display error message from google ([25cf594](https://github.com/AmruthPillai/Reactive-Resume/commit/25cf594eb948e1c2d6157028ee1fff2799df5f92))
### [3.4.7](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.6...v3.4.7) (2022-06-30)
### Bug Fixes
* **mui:** update mui datepickers to newer package ([bfb48e3](https://github.com/AmruthPillai/Reactive-Resume/commit/bfb48e3aa7e0575922841522edc1d38544d1884f))
### [3.4.6](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.5...v3.4.6) (2022-06-19)
## [3.6.0](https://github.com/dvd741-a/Reactive-Resume/compare/v3.3.4...v3.6.0) (2022-06-05)
### Features
* **all:** upgrade to v3.4.0 ([87d381f](https://github.com/dvd741-a/Reactive-Resume/commit/87d381fe8eab9ca4624df5de6e8b9ab18a072b67))
* **i18n:** add Hungrarian (Magyar) language ([35fe4e2](https://github.com/dvd741-a/Reactive-Resume/commit/35fe4e27744b6f7325b25db2cf3b626ed8598623))
### Bug Fixes
* **i18n:** fix language mismatch in exported pdf ([62fd63e](https://github.com/dvd741-a/Reactive-Resume/commit/62fd63e41fe10fba843a40fb08191f5944f2b2fc))
* **typeorm:** update typeorm to latest 0.2.x for secpatch ([5bdb92b](https://github.com/dvd741-a/Reactive-Resume/commit/5bdb92b1cff9e56879f9bbf31801d6554a00a8d5))
## [3.5.0](https://github.com/dvd741-a/Reactive-Resume/compare/v3.3.4...v3.5.0) (2022-06-05)
### Features
* **all:** upgrade to v3.4.0 ([87d381f](https://github.com/dvd741-a/Reactive-Resume/commit/87d381fe8eab9ca4624df5de6e8b9ab18a072b67))
* **i18n:** add Hungrarian (Magyar) language ([35fe4e2](https://github.com/dvd741-a/Reactive-Resume/commit/35fe4e27744b6f7325b25db2cf3b626ed8598623))
### Bug Fixes
* **i18n:** fix language mismatch in exported pdf ([62fd63e](https://github.com/dvd741-a/Reactive-Resume/commit/62fd63e41fe10fba843a40fb08191f5944f2b2fc))
* **typeorm:** update typeorm to latest 0.2.x for secpatch ([5bdb92b](https://github.com/dvd741-a/Reactive-Resume/commit/5bdb92b1cff9e56879f9bbf31801d6554a00a8d5))
### [3.4.5](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.4...v3.4.5) (2022-05-24)
### Bug Fixes
* **i18n:** fix language mismatch in exported pdf ([62fd63e](https://github.com/AmruthPillai/Reactive-Resume/commit/62fd63e41fe10fba843a40fb08191f5944f2b2fc))
## [3.4.4](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.3...v3.4.4) (2022-05-02)
### Features
* **i18n:** add Hungrarian (Magyar) language ([35fe4e2](https://github.com/AmruthPillai/Reactive-Resume/commit/35fe4e27744b6f7325b25db2cf3b626ed8598623))
### [3.4.3](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.2...v3.4.3) (2022-05-01)
### [3.4.2](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.1...v3.4.2) (2022-04-30)
### [3.4.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.0...v3.4.1) (2022-04-30)
### Bug Fixes
* **typeorm:** update typeorm to latest 0.2.x for secpatch ([5bdb92b](https://github.com/AmruthPillai/Reactive-Resume/commit/5bdb92b1cff9e56879f9bbf31801d6554a00a8d5))
### [3.4.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.3...v3.4.0) (2022-04-30)
### [3.3.4](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.3...v3.3.4) (2022-04-09)
### [3.3.3](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.2...v3.3.3) (2022-04-09)
### Features
* **profile:** add XING profile icon ([1e59f73](https://github.com/AmruthPillai/Reactive-Resume/commit/1e59f73f79a91d0264c0d2108906ee89d4eb27f8)), closes [#821](https://github.com/AmruthPillai/Reactive-Resume/issues/821)
* **s3:** implement non-ephemeral storage through S3/DO Spaces ([feb911a](https://github.com/AmruthPillai/Reactive-Resume/commit/feb911aea06bacf58ea933d2803a2a89fe36e57b))
### [3.3.2](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.1...v3.3.2) (2022-04-08)
### Bug Fixes
* **types/react:** downgrade to <18 ([fc77b54](https://github.com/AmruthPillai/Reactive-Resume/commit/fc77b548d8d61530b2d158ff83f088bed12d5080))
### [3.3.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.0...v3.3.1) (2022-04-08)
## [3.3.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.11...v3.3.0) (2022-04-08)
### Features
* **upgrade:** changes to code to support new template ([1df7810](https://github.com/AmruthPillai/Reactive-Resume/commit/1df78100ca0667ce9b7834cf2c25384eb21c67c2))
### What's Changed
* New Crowdin updates by @AmruthPillai in https://github.com/AmruthPillai/Reactive-Resume/pull/791
* Bump org.jetbrains.kotlin.android from 1.6.10 to 1.6.20 in /app by @dependabot in https://github.com/AmruthPillai/Reactive-Resume/pull/812
* New Crowdin updates by @AmruthPillai in https://github.com/AmruthPillai/Reactive-Resume/pull/806
* A new template - Leafish by @klejejs in https://github.com/AmruthPillai/Reactive-Resume/pull/811
* Automatic multi-platform Docker image build by @schklom in https://github.com/AmruthPillai/Reactive-Resume/pull/817
### New Contributors
* @klejejs made their first contribution in https://github.com/AmruthPillai/Reactive-Resume/pull/811
* @schklom made their first contribution in https://github.com/AmruthPillai/Reactive-Resume/pull/817
### [3.2.11](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.10...v3.2.11) (2022-03-28)
### [3.2.10](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.9...v3.2.10) (2022-03-24)
### Features
* **i18n:** add portuguese (pt) language to i18n locales ([7f1c82c](https://github.com/AmruthPillai/Reactive-Resume/commit/7f1c82cd9185ebb44486a16132eb44d5c2fb747a))
### [3.2.9](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.8...v3.2.9) (2022-03-21)
### Features
* **i18n:** add nl and ru i18n locales to app ([03cbf22](https://github.com/AmruthPillai/Reactive-Resume/commit/03cbf22c9bee96cac8f228830b67b44529b7ecee))
### [3.2.8](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.7...v3.2.8) (2022-03-18)
### Features
* **client/theme:** add theme switcher to landing page ([8f5632c](https://github.com/AmruthPillai/Reactive-Resume/commit/8f5632c5ad0bc8a4b3028c2806365717fedd78c9))
* **flags:** introduce flags, disable_user_signups ([b6267d0](https://github.com/AmruthPillai/Reactive-Resume/commit/b6267d07ba2dcaed0da3946d136a0a9a01c441d5)), closes [#698](https://github.com/AmruthPillai/Reactive-Resume/issues/698)
* **i18n:** add Vietnamese language to i18n locales ([4390bcc](https://github.com/AmruthPillai/Reactive-Resume/commit/4390bccfb9764f2d2730ec3a124b7befb6792e9a))
### Bug Fixes
* **client/create-rename-slug:** fix slug accepting apostrophes and other special characters ([1facd2a](https://github.com/AmruthPillai/Reactive-Resume/commit/1facd2ad111cd9d990c808b3956d3915e8711acd)), closes [#706](https://github.com/AmruthPillai/Reactive-Resume/issues/706)
* **disable_user_signups:** hide create account link under flag ([80acfe9](https://github.com/AmruthPillai/Reactive-Resume/commit/80acfe97c74bfa05b719285b19144144f3f7c5ba))
### [3.2.7](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.6...v3.2.7) (2022-03-18)
### Features
* **i18n:** add Malayalam (മലയ) language to i18n locales ([3a2e62b](https://github.com/AmruthPillai/Reactive-Resume/commit/3a2e62be4c9acc14f17277c060cc9ea2c417a478))
### Bug Fixes
* **printer/i18n:** fix dates not showing up in resume language when printing ([90321e1](https://github.com/AmruthPillai/Reactive-Resume/commit/90321e1284409ab9442883c04a9b4c591d36f95d)), closes [#729](https://github.com/AmruthPillai/Reactive-Resume/issues/729)
### [3.2.6](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.5...v3.2.6) (2022-03-17)
### Features
* **client/auth/google:** disable google login/registration if GOOGLE_CLIENT_ID is not in ENV ([7f0ee40](https://github.com/AmruthPillai/Reactive-Resume/commit/7f0ee40af4acc7eb41514406ecee3218ace9e891)), closes [#724](https://github.com/AmruthPillai/Reactive-Resume/issues/724)
* **i18n:** add arabic language to i18n locale ([39fa6da](https://github.com/AmruthPillai/Reactive-Resume/commit/39fa6da5dd77ce2e12e81530fa18c2eac722c1f2))
### Bug Fixes
* **i18n:** add missing languages to dayjs date wrapper locales ([9e6dafc](https://github.com/AmruthPillai/Reactive-Resume/commit/9e6dafc8cada5c01559894905996b81004bedaec)), closes [#719](https://github.com/AmruthPillai/Reactive-Resume/issues/719)
* **json-export:** add mimeType and charset to JSON export ([b3ff780](https://github.com/AmruthPillai/Reactive-Resume/commit/b3ff7805cd856a52900d9acef0554867d8ce0b01)), closes [#726](https://github.com/AmruthPillai/Reactive-Resume/issues/726)
* **linkedin:** fix skill modal crashing when importing from linkedin ([a02b85b](https://github.com/AmruthPillai/Reactive-Resume/commit/a02b85b4bb1c4a1499aacddeac7bc59bcb1f7adb)), closes [#718](https://github.com/AmruthPillai/Reactive-Resume/issues/718)
### [3.2.5](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.4...v3.2.5) (2022-03-16)
### Features
* **i18n:** add danish, polish and turkish locales to i18n ([97e9432](https://github.com/AmruthPillai/Reactive-Resume/commit/97e9432d6bd887e666a3443fbfde9a92cef53965))
### Bug Fixes
* **client/templates:** fix text veering off of artboard in most templates ([b2f1fb3](https://github.com/AmruthPillai/Reactive-Resume/commit/b2f1fb3a5502988a49c5cd3e496d9d165f5c1792)), closes [#702](https://github.com/AmruthPillai/Reactive-Resume/issues/702)
### [3.2.4](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.3...v3.2.4) (2022-03-14)
### [3.2.3](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.2...v3.2.3) (2022-03-14)

View File

@ -1,11 +1,12 @@
<img src="https://i.imgur.com/pc8Ingg.png" alt="Reactive Resume" width="256px" height="256px" />
<img src="https://github.com/AmruthPillai/Reactive-Resume/blob/main/docs/static/logo.svg" alt="Reactive Resume" width="256px" height="256px" />
# Reactive Resume
![Project Version](https://img.shields.io/github/package-json/v/AmruthPillai/Reactive-Resume?style=flat-square)
![Project License](https://img.shields.io/github/license/AmruthPillai/Reactive-Resume?style=flat-square)
[![Project Version](https://img.shields.io/github/package-json/v/AmruthPillai/Reactive-Resume?style=flat-square)](https://github.com/AmruthPillai/Reactive-Resume/releases)
[![Project License](https://img.shields.io/github/license/AmruthPillai/Reactive-Resume?style=flat-square)](https://github.com/AmruthPillai/Reactive-Resume/blob/main/LICENSE)
[![Crowdin](https://badges.crowdin.net/reactive-resume/localized.svg)](https://translate.rxresu.me)
[![Docker Pulls](https://img.shields.io/docker/pulls/amruthpillai/reactive-resume?style=flat-square)](https://hub.docker.com/r/amruthpillai/reactive-resume)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/AmruthPillai/Reactive-Resume/Build%20and%20Push%20Docker%20Image?label=docker%20build&style=flat-square)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FAmruthPillai%2FReactive-Resume.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FAmruthPillai%2FReactive-Resume?ref=badge_shield)
## [Go to App](https://rxresu.me) | [Docs](https://docs.rxresu.me)
@ -14,6 +15,23 @@ Reactive Resume is a free and open source resume builder thats built to make
You have complete control over what goes into your resume, how it looks, what colors, what templates, even the layout in which sections placed. Want a dark mode resume? Its as easy as editing 3 values and youre done. You dont need to wait to see your changes either. Everything you type, everything you change, appears immediately on your resume and gets updated in real time.
## Table of Contents
- [Reactive Resume](#reactive-resume)
- [Go to App | [Docs](https://docs.rxresu.me)](#go-to-app--docs)
- [Table of Contents](#table-of-contents)
- [Features](#features)
- [Languages](#languages)
- [Tutorial](#tutorial)
- [Build from Source](#build-from-source)
- [Contributing](#contributing)
- [Report Bugs and Feature Requests](#report-bugs-and-feature-requests)
- [Donations](#donations)
- [💸 PayPal](#-paypal)
- [Infrastructure](#infrastructure)
- [Contributors Wall](#contributors-wall)
- [License](#license)
## Features
- Free, forever
@ -36,16 +54,33 @@ You have complete control over what goes into your resume, how it looks, what co
## Languages
- Arabic (اَلْعَرَبِيَّةُ)
- Bengali (বাংলা)
- Chinese (中文)
- Czech (čeština)
- Danish (Dansk)
- Dutch (Nederlands)
- English
- French (Français)
- German (Deutsch)
- Greek (Ελληνικά)
- Hebrew (Ivrit)
- Hindi (हिन्दी)
- Hungarian (Magyar)
- Indonesian (Bahasa Indonesia)
- Italian (Italiano)
- Kannada (ಕನ್ನಡ)
- Malayalam (മലയാളം)
- Odia (ଓଡ଼ିଆ)
- Persian (Farsi)
- Polish (Polski)
- Portuguese (Português)
- Russian (русский)
- Spanish (Español)
- Swedish (Svenska)
- Tamil (தமிழ்)
- Turkish (Türkçe)
- Vietnamese (Tiếng Việt)
Help by [translating Reactive Resume](https://translate.rxresu.me) to your language!
@ -69,13 +104,13 @@ This project makes use of [conventional commits](https://www.conventionalcommits
NOTE: Be sure to merge the latest from `main` before making a pull request!
## Bugs? Feature Requests?
## Report Bugs and Feature Requests
Use the [GitHub Issues](https://github.com/AmruthPillai/Reactive-Resume/issues/new/choose) platform to notify me about bugs or new features that you would like to see in Reactive Resume. Please check before creating new issues as there might already be one.
## Donations
Reactive Resume would be nothing without the folks who supported me and kept the project alive in the beginning, and your cotinued support is what keeps me going. If you found Reactive Resume to be useful, helpful or just insightful and appreciate the effort I took to make the project, please consider donating as little or as much as your can.
Reactive Resume would be nothing without the folks who supported me and kept the project alive in the beginning, and your continued support is what keeps me going. If you found Reactive Resume to be useful, helpful or just insightful and appreciate the effort I took to make the project, please consider donating as little or as much as you can.
### [💸 PayPal](https://paypal.me/RajaRajanA)
@ -93,6 +128,14 @@ Reactive Resume would be nothing without the folks who supported me and kept the
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/PoweredByDO/DO_Powered_by_Badge_blue.svg" width="200px" />
</a>
## Contributors Wall
<a href="https://github.com/AmruthPillai/Reactive-Resume/graphs/contributors">
<img src="https://contrib.rocks/image?repo=AmruthPillai/Reactive-Resume" />
</a>
_Note: It may take up to 24h for the [contrib.rocks](https://contrib.rocks/image?repo=AmruthPillai/Reactive-Resume) plugin to update because it's refreshed once a day._
## License
Reactive Resume is packaged and distributed using the [MIT License](https://choosealicense.com/licenses/mit/) which allows for commercial use, distribution, modification and private use provided that all copies of the software contain the same license and copyright.

13
SECURITY.md Normal file
View File

@ -0,0 +1,13 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 3.x.x | :white_check_mark: |
| 2.x.x | :x: |
| 1.x.x | :x: |
## Reporting a Vulnerability
Create an issue on GitHub or send me an email through the contact form on my website at https://amruthpillai.com/

View File

@ -1,7 +1,7 @@
plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
}
task clean(type: Delete) {

View File

@ -3,6 +3,7 @@
"ignorePatterns": [".next", "__ENV.js"],
"rules": {
"@next/next/no-img-element": "off",
"@next/next/no-sync-scripts": "off"
"@next/next/no-sync-scripts": "off",
"@next/next/no-html-link-for-pages": ["error", "pages"]
}
}

5
client/.gitignore vendored
View File

@ -36,4 +36,7 @@ yarn-error.log*
*.tsbuildinfo
# react-env
__ENV.js
__ENV.js
# next-sitemap
sitemap*.xml

View File

@ -1,4 +1,4 @@
FROM node:16-alpine as dependencies
FROM node:lts-alpine as dependencies
RUN apk add --no-cache curl g++ make python3 \
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
@ -11,7 +11,7 @@ COPY ./client/package.json ./client/package.json
RUN pnpm install --frozen-lockfile
FROM node:16-alpine as builder
FROM node:lts-alpine as builder
RUN apk add --no-cache curl g++ make python3 \
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
@ -27,7 +27,7 @@ COPY --from=dependencies /app/client/node_modules ./client/node_modules
RUN pnpm run build:schema
RUN pnpm run build:client
FROM node:16-alpine as production
FROM node:lts-alpine as production
WORKDIR /app
@ -49,4 +49,7 @@ EXPOSE 3000
ENV PORT 3000
HEALTHCHECK --interval=30s --timeout=20s --retries=3 --start-period=15s \
CMD curl -fSs 127.0.0.1:3000 || exit 1
CMD [ "pnpm", "run", "start:client" ]

View File

@ -52,7 +52,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
const url = getResumeUrl(resume, { withHost: true });
await navigator.clipboard.writeText(url);
toast.success(t('common.toast.success.resume-link-copied'));
toast.success(t<string>('common.toast.success.resume-link-copied'));
};
const handleExportPDF = async () => {
@ -75,19 +75,19 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
})}
>
<div className={styles.controller}>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-in') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-in')}>
<ButtonBase onClick={() => zoomIn(0.25)}>
<ZoomIn fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-out') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-out')}>
<ButtonBase onClick={() => zoomOut(0.25)}>
<ZoomOut fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.center-artboard') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.center-artboard')}>
<ButtonBase onClick={() => centerView(0.95)}>
<FilterCenterFocus fontSize="medium" />
</ButtonBase>
@ -98,7 +98,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
{isDesktop && (
<>
{pages.length > 1 && (
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-orientation') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-orientation')}>
<ButtonBase onClick={handleTogglePageOrientation}>
{orientation === 'vertical' ? (
<AlignHorizontalCenter fontSize="medium" />
@ -109,13 +109,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
</Tooltip>
)}
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-page-break-line') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-page-break-line')}>
<ButtonBase onClick={handleTogglePageBreakLine}>
<InsertPageBreak fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-sidebars') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-sidebars')}>
<ButtonBase onClick={handleToggleSidebar}>
<ViewSidebar fontSize="medium" />
</ButtonBase>
@ -125,13 +125,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
</>
)}
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.copy-link') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.copy-link')}>
<ButtonBase onClick={handleCopyLink}>
<Link fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.export-pdf') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.export-pdf')}>
<ButtonBase onClick={handleExportPDF} disabled={isLoading}>
<Download fontSize="medium" />
</ButtonBase>

View File

@ -133,7 +133,7 @@ const Header = () => {
const url = getResumeUrl(resume, { withHost: true });
await navigator.clipboard.writeText(url);
toast.success(t('common.toast.success.resume-link-copied'));
toast.success(t<string>('common.toast.success.resume-link-copied'));
};
return (
@ -166,14 +166,14 @@ const Header = () => {
<ListItemIcon>
<DriveFileRenameOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.rename')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.rename')}</ListItemText>
</MenuItem>
<MenuItem onClick={handleDuplicate}>
<ListItemIcon>
<CopyAll className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.duplicate')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.duplicate')}</ListItemText>
</MenuItem>
{resume.public ? (
@ -181,27 +181,27 @@ const Header = () => {
<ListItemIcon>
<LinkIcon className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.share-link')}</ListItemText>
</MenuItem>
) : (
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.share-link') as string}>
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.share-link')}>
<div>
<MenuItem>
<ListItemIcon>
<LinkIcon className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.share-link')}</ListItemText>
</MenuItem>
</div>
</Tooltip>
)}
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.delete') as string}>
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.delete')}>
<MenuItem onClick={handleDelete}>
<ListItemIcon>
<Delete className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.delete')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.delete')}</ListItemText>
</MenuItem>
</Tooltip>
</Menu>

View File

@ -48,9 +48,7 @@ const Page: React.FC<Props> = ({ page, showPageNumbers = false }) => {
</div>
{showPageNumbers && (
<h4 className={styles.pageNumber}>
{t('builder.common.glossary.page')} {page + 1}
</h4>
<h4 className={styles.pageNumber}>{`${t<string>('builder.common.glossary.page')} ${page + 1}`}</h4>
)}
</div>
);

View File

@ -81,14 +81,14 @@ const LeftSidebar = () => {
arrow
key={id}
placement="right"
title={get(sections, `${id}.name`, t<string>(`builder.leftSidebar.sections.${id}.heading`))}
title={get(sections, `${id}.name`, t<string>(`builder.leftSidebar.sections.${id}.heading`)) as string}
>
<IconButton onClick={() => handleClick(id)}>{icon}</IconButton>
</Tooltip>
))}
{customSections.map(({ id }) => (
<Tooltip key={id} title={get(sections, `${id}.name`, '')} placement="right" arrow>
<Tooltip key={id} title={get(sections, `${id}.name`, '') as string} placement="right" arrow>
<IconButton onClick={() => handleClick(id)}>
<Star />
</IconButton>
@ -114,7 +114,9 @@ const LeftSidebar = () => {
<div className="py-6 text-right">
<Button fullWidth variant="outlined" startIcon={<Add />} onClick={handleAddSection}>
{t('builder.common.actions.add', { token: t('builder.leftSidebar.sections.section.heading') })}
{t<string>('builder.common.actions.add', {
token: t<string>('builder.leftSidebar.sections.section.heading'),
})}
</Button>
</div>
</main>

View File

@ -24,7 +24,7 @@ const Basics = () => {
return (
<>
<Heading path="sections.basics" name={t('builder.leftSidebar.sections.basics.heading')} />
<Heading path="sections.basics" name={t<string>('builder.leftSidebar.sections.basics.heading')} />
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div className="grid items-center gap-4 sm:col-span-2 sm:grid-cols-3">
@ -33,10 +33,10 @@ const Basics = () => {
</div>
<div className="grid gap-2 w-full sm:col-span-2">
<ResumeInput label={t('builder.leftSidebar.sections.basics.name.label')} path="basics.name" />
<ResumeInput label={t<string>('builder.leftSidebar.sections.basics.name.label')} path="basics.name" />
<Button variant="outlined" startIcon={<PhotoFilter />} onClick={handleClick}>
{t('builder.leftSidebar.sections.basics.actions.photo-filters')}
{t<string>('builder.leftSidebar.sections.basics.actions.photo-filters')}
</Button>
<Popover
@ -57,20 +57,30 @@ const Basics = () => {
</div>
</div>
<ResumeInput label={t('builder.common.form.email.label')} path="basics.email" className="sm:col-span-2" />
<ResumeInput label={t('builder.common.form.phone.label')} path="basics.phone" />
<ResumeInput label={t('builder.common.form.url.label')} path="basics.website" />
<ResumeInput
type="date"
label={t<string>('builder.leftSidebar.sections.basics.birthdate.label')}
path="basics.birthdate"
className="sm:col-span-2"
/>
<ResumeInput
label={t<string>('builder.common.form.email.label')}
path="basics.email"
className="sm:col-span-2"
/>
<ResumeInput label={t<string>('builder.common.form.phone.label')} path="basics.phone" />
<ResumeInput label={t<string>('builder.common.form.url.label')} path="basics.website" />
<Divider className="sm:col-span-2" />
<ResumeInput
label={t('builder.leftSidebar.sections.basics.headline.label')}
label={t<string>('builder.leftSidebar.sections.basics.headline.label')}
path="basics.headline"
className="sm:col-span-2"
/>
<ResumeInput
type="textarea"
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
path="basics.summary"
className="sm:col-span-2"
markdownSupported

View File

@ -8,19 +8,28 @@ const Location = () => {
return (
<>
<Heading path="sections.location" name={t('builder.leftSidebar.sections.location.heading')} />
<Heading path="sections.location" name={t<string>('builder.leftSidebar.sections.location.heading')} />
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<ResumeInput
label={t('builder.leftSidebar.sections.location.address.label')}
label={t<string>('builder.leftSidebar.sections.location.address.label')}
path="basics.location.address"
className="sm:col-span-2"
/>
<ResumeInput label={t('builder.leftSidebar.sections.location.city.label')} path="basics.location.city" />
<ResumeInput label={t('builder.leftSidebar.sections.location.region.label')} path="basics.location.region" />
<ResumeInput label={t('builder.leftSidebar.sections.location.country.label')} path="basics.location.country" />
<ResumeInput
label={t('builder.leftSidebar.sections.location.postal-code.label')}
label={t<string>('builder.leftSidebar.sections.location.city.label')}
path="basics.location.city"
/>
<ResumeInput
label={t<string>('builder.leftSidebar.sections.location.region.label')}
path="basics.location.region"
/>
<ResumeInput
label={t<string>('builder.leftSidebar.sections.location.country.label')}
path="basics.location.country"
/>
<ResumeInput
label={t<string>('builder.leftSidebar.sections.location.postal-code.label')}
path="basics.location.postalCode"
/>
</div>

View File

@ -32,7 +32,7 @@ const PhotoFilters = () => {
return (
<div className="flex flex-col gap-2 p-5 dark:bg-neutral-800">
<div>
<h4 className="font-medium">{t('builder.leftSidebar.sections.basics.photo-filters.size.heading')}</h4>
<h4 className="font-medium">{t<string>('builder.leftSidebar.sections.basics.photo-filters.size.heading')}</h4>
<div className="mx-2">
<Slider
@ -54,18 +54,20 @@ const PhotoFilters = () => {
<Divider />
<div>
<h4 className="font-medium">{t('builder.leftSidebar.sections.basics.photo-filters.effects.heading')}</h4>
<h4 className="font-medium">
{t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.heading')}
</h4>
<div className="flex items-center">
<FormControlLabel
label={t('builder.leftSidebar.sections.basics.photo-filters.effects.grayscale.label') as string}
label={t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.grayscale.label')}
control={
<Checkbox color="secondary" checked={grayscale} onChange={(_, value) => handleSetGrayscale(value)} />
}
/>
<FormControlLabel
label={t('builder.leftSidebar.sections.basics.photo-filters.effects.border.label') as string}
label={t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.border.label')}
control={<Checkbox color="secondary" checked={border} onChange={(_, value) => handleSetBorder(value)} />}
/>
</div>
@ -74,7 +76,7 @@ const PhotoFilters = () => {
<Divider />
<div className="flex flex-col gap-2">
<h4 className="font-medium">{t('builder.leftSidebar.sections.basics.photo-filters.shape.heading')}</h4>
<h4 className="font-medium">{t<string>('builder.leftSidebar.sections.basics.photo-filters.shape.heading')}</h4>
<ToggleButtonGroup exclusive value={shape} onChange={(_, value) => handleChangeShape(value)}>
<ToggleButton size="small" value="square" className="w-14">

View File

@ -49,7 +49,7 @@ const PhotoUpload: React.FC = () => {
const file = event.target.files[0];
if (file.size > FILE_UPLOAD_MAX_SIZE) {
toast.error(t('common.toast.error.upload-photo-size'));
toast.error(t<string>('common.toast.error.upload-photo-size'));
return;
}
@ -67,8 +67,8 @@ const PhotoUpload: React.FC = () => {
<Tooltip
title={
isEmpty(photo.url)
? (t('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload') as string)
: (t('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove') as string)
? (t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload') as string)
: (t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove') as string)
}
>
<Avatar sx={{ width: 96, height: 96 }} src={photo.url} />

View File

@ -28,7 +28,7 @@ const Profiles = () => {
return (
<>
<Heading path="sections.profiles" name={t('builder.leftSidebar.sections.profiles.heading')} />
<Heading path="sections.profiles" name={t<string>('builder.leftSidebar.sections.profiles.heading')} />
<List
path="basics.profiles"
@ -40,8 +40,8 @@ const Profiles = () => {
<footer className="flex justify-end">
<Button variant="outlined" startIcon={<Add />} onClick={handleAdd}>
{t('builder.common.actions.add', {
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
{t<string>('builder.common.actions.add', {
token: t<string>('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
})}
</Button>
</footer>

View File

@ -74,7 +74,7 @@ const Section: React.FC<Props> = ({
<SectionSettings path={path} />
<Button variant="outlined" startIcon={<Add />} onClick={handleAdd}>
{t('builder.common.actions.add', { token: heading })}
{t<string>('builder.common.actions.add', { token: heading })}
</Button>
</footer>
</>

View File

@ -32,7 +32,7 @@ const SectionSettings: React.FC<Props> = ({ path }) => {
return (
<div>
<Tooltip title={t('builder.common.columns.tooltip') as string}>
<Tooltip title={t<string>('builder.common.columns.tooltip')}>
<ButtonBase onClick={handleClick} sx={{ padding: 1, borderRadius: 1 }} className="opacity-50 hover:opacity-75">
<ViewWeek /> <span className="ml-1.5 text-xs">{columns}</span>
</ButtonBase>
@ -48,7 +48,7 @@ const SectionSettings: React.FC<Props> = ({ path }) => {
}}
>
<div className="p-5 dark:bg-neutral-800">
<h4 className="mb-2 font-medium">{t('builder.common.columns.heading')}</h4>
<h4 className="mb-2 font-medium">{t<string>('builder.common.columns.heading')}</h4>
<ToggleButtonGroup exclusive value={columns} onChange={(_, value: number) => handleSetColumns(value)}>
{[1, 2, 3, 4].map((index) => (

View File

@ -25,7 +25,7 @@ const CustomCSS = () => {
return (
<>
<Heading path="metadata.css" name={t('builder.rightSidebar.sections.css.heading')} isHideable />
<Heading path="metadata.css" name={t<string>('builder.rightSidebar.sections.css.heading')} isHideable />
<Editor
height="200px"

View File

@ -19,12 +19,12 @@ const Export = () => {
const pdfListItemText = {
normal: {
primary: t('builder.rightSidebar.sections.export.pdf.normal.primary'),
secondary: t('builder.rightSidebar.sections.export.pdf.normal.secondary'),
primary: t<string>('builder.rightSidebar.sections.export.pdf.normal.primary'),
secondary: t<string>('builder.rightSidebar.sections.export.pdf.normal.secondary'),
},
loading: {
primary: t('builder.rightSidebar.sections.export.pdf.loading.primary'),
secondary: t('builder.rightSidebar.sections.export.pdf.loading.secondary'),
primary: t<string>('builder.rightSidebar.sections.export.pdf.loading.primary'),
secondary: t<string>('builder.rightSidebar.sections.export.pdf.loading.secondary'),
},
};
@ -34,9 +34,10 @@ const Export = () => {
const redactedResume = pick(resume, ['basics', 'sections', 'metadata', 'public']);
const jsonString = JSON.stringify(redactedResume, null, 4);
const jsonBlob = new Blob([jsonString], { type: 'application/json;charset=utf-8' });
const filename = `RxResume_JSONExport_${nanoid()}.json`;
download(jsonString, filename, 'application/json');
download(jsonBlob, filename);
};
const handleExportPDF = async () => {
@ -52,7 +53,7 @@ const Export = () => {
return (
<>
<Heading path="metadata.export" name={t('builder.rightSidebar.sections.export.heading')} />
<Heading path="metadata.export" name={t<string>('builder.rightSidebar.sections.export.heading')} />
<List sx={{ padding: 0 }}>
<ListItem sx={{ padding: 0 }}>
@ -60,8 +61,8 @@ const Export = () => {
<Schema />
<ListItemText
primary={t('builder.rightSidebar.sections.export.json.primary')}
secondary={t('builder.rightSidebar.sections.export.json.secondary')}
primary={t<string>('builder.rightSidebar.sections.export.json.primary')}
secondary={t<string>('builder.rightSidebar.sections.export.json.secondary')}
/>
</ListItemButton>
</ListItem>

View File

@ -60,9 +60,9 @@ const Layout = () => {
<>
<Heading
path="metadata.layout"
name={t('builder.rightSidebar.sections.layout.heading')}
name={t<string>('builder.rightSidebar.sections.layout.heading')}
action={
<Tooltip title={t('builder.rightSidebar.sections.layout.tooltip.reset-layout') as string}>
<Tooltip title={t<string>('builder.rightSidebar.sections.layout.tooltip.reset-layout')}>
<IconButton onClick={handleResetLayout}>
<Restore />
</IconButton>
@ -76,12 +76,16 @@ const Layout = () => {
<div key={pageIndex} className={styles.page}>
<div className="flex items-center justify-between pr-3">
<p className={styles.heading}>
{t('builder.common.glossary.page')} {pageIndex + 1}
{t<string>('builder.common.glossary.page')} {pageIndex + 1}
</p>
<div className={clsx(styles.delete, { hidden: pageIndex === 0 })}>
<Tooltip
title={t('builder.common.actions.delete', { token: t('builder.common.glossary.page') }) as string}
title={
t<string>('builder.common.actions.delete', {
token: t<string>('builder.common.glossary.page'),
}) as string
}
>
<IconButton size="small" onClick={() => handleDeletePage(pageIndex)}>
<Close fontSize="small" />
@ -113,7 +117,7 @@ const Layout = () => {
[styles.disabled]: !get(resumeSections, `${sectionId}.visible`, true),
})}
>
{get(resumeSections, `${sectionId}.name`)}
{get(resumeSections, `${sectionId}.name`, '') as string}
</div>
</div>
)}
@ -132,7 +136,7 @@ const Layout = () => {
<div className="flex items-center justify-end">
<Button variant="outlined" startIcon={<Add />} onClick={handleAddPage}>
{t('builder.common.actions.add', { token: t('builder.common.glossary.page') })}
{t<string>('builder.common.actions.add', { token: t<string>('builder.common.glossary.page') })}
</Button>
</div>
</DragDropContext>

View File

@ -12,39 +12,41 @@ const Links = () => {
return (
<>
<Heading path="metadata.links" name={t('builder.rightSidebar.sections.links.heading')} />
<Heading path="metadata.links" name={t<string>('builder.rightSidebar.sections.links.heading')} />
<div className={styles.container}>
<div className={styles.section}>
<h2>
<Savings fontSize="small" />
{t('builder.rightSidebar.sections.links.donate.heading')}
{t<string>('builder.rightSidebar.sections.links.donate.heading')}
</h2>
<p>{t('builder.rightSidebar.sections.links.donate.body')}</p>
<p>{t<string>('builder.rightSidebar.sections.links.donate.body')}</p>
<a href={DONATION_URL} target="_blank" rel="noreferrer">
<Button startIcon={<Coffee />}>{t('builder.rightSidebar.sections.links.donate.button')}</Button>
<Button startIcon={<Coffee />}>{t<string>('builder.rightSidebar.sections.links.donate.button')}</Button>
</a>
</div>
<div className={styles.section}>
<h2>
<BugReport fontSize="small" />
{t('builder.rightSidebar.sections.links.bugs-features.heading')}
{t<string>('builder.rightSidebar.sections.links.bugs-features.heading')}
</h2>
<p>{t('builder.rightSidebar.sections.links.bugs-features.body')}</p>
<p>{t<string>('builder.rightSidebar.sections.links.bugs-features.body')}</p>
<a href={GITHUB_ISSUES_URL} target="_blank" rel="noreferrer">
<Button startIcon={<GitHub />}>{t('builder.rightSidebar.sections.links.bugs-features.button')}</Button>
<Button startIcon={<GitHub />}>
{t<string>('builder.rightSidebar.sections.links.bugs-features.button')}
</Button>
</a>
</div>
<div>
<a href={GITHUB_URL} target="_blank" rel="noreferrer">
<Button variant="text" startIcon={<Link />}>
{t('builder.rightSidebar.sections.links.github')}
{t<string>('builder.rightSidebar.sections.links.github')}
</Button>
</a>
</div>

View File

@ -15,7 +15,7 @@ import dayjs from 'dayjs';
import get from 'lodash/get';
import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { useMemo } from 'react';
import { useMemo, useState } from 'react';
import { useMutation } from 'react-query';
import Heading from '@/components/shared/Heading';
@ -36,6 +36,8 @@ const Settings = () => {
const { locale, ...router } = useRouter();
const [confirmReset, setConfirmReset] = useState(false);
const resume = useAppSelector((state) => state.resume);
const theme = useAppSelector((state) => state.build.theme);
const pages = useAppSelector((state) => state.resume.metadata.layout);
@ -48,7 +50,7 @@ const Settings = () => {
const dateConfig: DateConfig = useMemo(() => get(resume, 'metadata.date'), [resume]);
const isDarkMode = useMemo(() => theme === 'dark', [theme]);
const exampleString = useMemo(() => `Eg. ${dayjs().format(dateConfig.format)}`, [dateConfig.format]);
const exampleString = useMemo(() => `Eg. ${dayjs().utc().format(dateConfig.format)}`, [dateConfig.format]);
const themeString = useMemo(() => (isDarkMode ? 'Matte Black Everything' : 'As bright as your future'), [isDarkMode]);
const { mutateAsync: loadSampleDataMutation } = useMutation<Resume, ServerError, LoadSampleDataParams>(
@ -78,20 +80,25 @@ const Settings = () => {
};
const handleResetResume = async () => {
await resetResumeMutation({ id });
if (!confirmReset) {
return setConfirmReset(true);
}
queryClient.invalidateQueries(`resume/${username}/${slug}`);
await resetResumeMutation({ id });
await queryClient.invalidateQueries(`resume/${username}/${slug}`);
setConfirmReset(false);
};
return (
<>
<Heading path="metadata.settings" name={t('builder.rightSidebar.sections.settings.heading')} />
<Heading path="metadata.settings" name={t<string>('builder.rightSidebar.sections.settings.heading')} />
<List sx={{ padding: 0 }}>
{/* Global Settings */}
<>
<ListSubheader className="rounded">
{t('builder.rightSidebar.sections.settings.global.heading')}
{t<string>('builder.rightSidebar.sections.settings.global.heading')}
</ListSubheader>
<ListItem>
@ -99,7 +106,7 @@ const Settings = () => {
<Palette />
</ListItemIcon>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.global.theme.primary')}
primary={t<string>('builder.rightSidebar.sections.settings.global.theme.primary')}
secondary={themeString}
/>
<ThemeSwitch checked={isDarkMode} onChange={(_, value: boolean) => handleSetTheme(value)} />
@ -108,8 +115,8 @@ const Settings = () => {
<ListItem className="flex-col">
<ListItemText
className="w-full"
primary={t('builder.rightSidebar.sections.settings.global.date.primary')}
secondary={t('builder.rightSidebar.sections.settings.global.date.secondary')}
primary={t<string>('builder.rightSidebar.sections.settings.global.date.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.global.date.secondary')}
/>
<Autocomplete<string, false, boolean, false>
disableClearable
@ -124,8 +131,8 @@ const Settings = () => {
<ListItem className="flex-col">
<ListItemText
className="w-full"
primary={t('builder.rightSidebar.sections.settings.global.language.primary')}
secondary={t('builder.rightSidebar.sections.settings.global.language.secondary')}
primary={t<string>('builder.rightSidebar.sections.settings.global.language.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.global.language.secondary')}
/>
<Autocomplete<Language, false, boolean, false>
disableClearable
@ -148,15 +155,17 @@ const Settings = () => {
{/* Page Settings */}
<>
<ListSubheader className="rounded">{t('builder.rightSidebar.sections.settings.page.heading')}</ListSubheader>
<ListSubheader className="rounded">
{t<string>('builder.rightSidebar.sections.settings.page.heading')}
</ListSubheader>
<ListItem>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.page.orientation.primary')}
primary={t<string>('builder.rightSidebar.sections.settings.page.orientation.primary')}
secondary={
pages.length === 1
? t('builder.rightSidebar.sections.settings.page.orientation.disabled')
: t('builder.rightSidebar.sections.settings.page.orientation.secondary')
? t<string>('builder.rightSidebar.sections.settings.page.orientation.disabled')
: t<string>('builder.rightSidebar.sections.settings.page.orientation.secondary')
}
/>
<Switch
@ -169,8 +178,8 @@ const Settings = () => {
<ListItem>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.page.break-line.primary')}
secondary={t('builder.rightSidebar.sections.settings.page.break-line.secondary')}
primary={t<string>('builder.rightSidebar.sections.settings.page.break-line.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.page.break-line.secondary')}
/>
<Switch color="secondary" checked={breakLine} onChange={() => dispatch(togglePageBreakLine())} />
</ListItem>
@ -179,7 +188,7 @@ const Settings = () => {
{/* Resume Settings */}
<>
<ListSubheader className="rounded">
{t('builder.rightSidebar.sections.settings.resume.heading')}
{t<string>('builder.rightSidebar.sections.settings.resume.heading')}
</ListSubheader>
<ListItem>
@ -188,8 +197,8 @@ const Settings = () => {
<Anchor />
</ListItemIcon>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.resume.sample.primary')}
secondary={t('builder.rightSidebar.sections.settings.resume.sample.secondary')}
primary={t<string>('builder.rightSidebar.sections.settings.resume.sample.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.resume.sample.secondary')}
/>
</ListItemButton>
</ListItem>
@ -200,8 +209,12 @@ const Settings = () => {
<DeleteForever />
</ListItemIcon>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.resume.reset.primary')}
secondary={t('builder.rightSidebar.sections.settings.resume.reset.secondary')}
primary={
confirmReset
? 'Are you sure?'
: t<string>('builder.rightSidebar.sections.settings.resume.reset.primary')
}
secondary={t<string>('builder.rightSidebar.sections.settings.resume.reset.secondary')}
/>
</ListItemButton>
</ListItem>

View File

@ -29,19 +29,19 @@ const Sharing = () => {
await navigator.clipboard.writeText(text);
toast.success(t('common.toast.success.resume-link-copied'));
toast.success(t<string>('common.toast.success.resume-link-copied'));
};
return (
<>
<Heading path="metadata.sharing" name={t('builder.rightSidebar.sections.sharing.heading')} />
<Heading path="metadata.sharing" name={t<string>('builder.rightSidebar.sections.sharing.heading')} />
<List sx={{ padding: 0 }}>
<ListItem className="flex flex-col" sx={{ padding: 0 }}>
<div className="flex w-full items-center justify-between">
<ListItemText
primary={t('builder.rightSidebar.sections.sharing.visibility.title')}
secondary={t('builder.rightSidebar.sections.sharing.visibility.subtitle')}
primary={t<string>('builder.rightSidebar.sections.sharing.visibility.title')}
secondary={t<string>('builder.rightSidebar.sections.sharing.visibility.subtitle')}
/>
<Switch color="secondary" checked={isPublic} onChange={(_, value) => handleSetVisibility(value)} />
</div>
@ -63,7 +63,7 @@ const Sharing = () => {
<div className="mt-1 flex w-full">
<FormControlLabel
label={t('builder.rightSidebar.sections.sharing.short-url.label') as string}
label={t<string>('builder.rightSidebar.sections.sharing.short-url.label')}
control={
<Checkbox className="mr-1" checked={showShortUrl} onChange={(_, value) => setShowShortUrl(value)} />
}

View File

@ -24,7 +24,7 @@ const Templates = () => {
return (
<>
<Heading path="metadata.templates" name={t('builder.rightSidebar.sections.templates.heading')} />
<Heading path="metadata.templates" name={t<string>('builder.rightSidebar.sections.templates.heading')} />
<div className={styles.container}>
{Object.values(templateMap).map((template) => (

View File

@ -19,12 +19,12 @@ const Theme = () => {
const { background, text, primary } = useAppSelector<ThemeType>((state) => get(state.resume, 'metadata.theme'));
const handleChange = (property: string, color: string) => {
dispatch(setResumeState({ path: `metadata.theme.${property}`, value: color }));
dispatch(setResumeState({ path: `metadata.theme.${property}`, value: color[0] !== '#' ? `#${color}` : color }));
};
return (
<>
<Heading path="metadata.theme" name={t('builder.rightSidebar.sections.theme.heading')} />
<Heading path="metadata.theme" name={t<string>('builder.rightSidebar.sections.theme.heading')} />
<div className={styles.container}>
<div className={styles.colorOptions}>
@ -34,18 +34,18 @@ const Theme = () => {
</div>
<ColorPicker
label={t('builder.rightSidebar.sections.theme.form.primary.label')}
label={t<string>('builder.rightSidebar.sections.theme.form.primary.label')}
color={primary}
className="col-span-2"
onChange={(color) => handleChange('primary', color)}
/>
<ColorPicker
label={t('builder.rightSidebar.sections.theme.form.background.label')}
label={t<string>('builder.rightSidebar.sections.theme.form.background.label')}
color={background}
onChange={(color) => handleChange('background', color)}
/>
<ColorPicker
label={t('builder.rightSidebar.sections.theme.form.text.label')}
label={t<string>('builder.rightSidebar.sections.theme.form.text.label')}
color={text}
onChange={(color) => handleChange('text', color)}
/>

View File

@ -64,7 +64,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
step={1}
marks={[
{ value: 12, label: '12px' },
{ value: 24, label: t('builder.rightSidebar.sections.typography.form.font-size.label') },
{ value: 24, label: t<string>('builder.rightSidebar.sections.typography.form.font-size.label') },
{ value: 36, label: '36px' },
]}
valueLabelDisplay="auto"
@ -82,7 +82,10 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
value={fonts.find((font) => font.family === family[category])}
onChange={(_, font: Font | null) => handleChange('family', font)}
renderInput={(params) => (
<TextField {...params} label={t('builder.rightSidebar.sections.typography.form.font-family.label')} />
<TextField
{...params}
label={t<string>('builder.rightSidebar.sections.typography.form.font-family.label')}
/>
)}
/>
</div>
@ -95,10 +98,13 @@ const Typography = () => {
return (
<>
<Heading path="metadata.typography" name={t('builder.rightSidebar.sections.typography.heading')} />
<Heading path="metadata.typography" name={t<string>('builder.rightSidebar.sections.typography.heading')} />
<Widgets label={t('builder.rightSidebar.sections.typography.widgets.headings.label')} category="heading" />
<Widgets label={t('builder.rightSidebar.sections.typography.widgets.body.label')} category="body" />
<Widgets
label={t<string>('builder.rightSidebar.sections.typography.widgets.headings.label')}
category="heading"
/>
<Widgets label={t<string>('builder.rightSidebar.sections.typography.widgets.body.label')} category="body" />
</>
);
};

View File

@ -94,7 +94,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
const url = getResumeUrl(resume, { withHost: true });
await navigator.clipboard.writeText(url);
toast.success(t('common.toast.success.resume-link-copied'));
toast.success(t<string>('common.toast.success.resume-link-copied'));
};
const handleDelete = async () => {
@ -124,7 +124,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
<footer>
<div className={styles.meta}>
<p>{resume.name}</p>
<p>{t('dashboard.resume.timestamp', { timestamp: getRelativeTime(resume.updatedAt) })}</p>
<p>{t<string>('dashboard.resume.timestamp', { timestamp: getRelativeTime(resume.updatedAt) })}</p>
</div>
<ButtonBase className={styles.menu} onClick={handleOpenMenu}>
@ -136,21 +136,21 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
<ListItemIcon>
<OpenInNew className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.open')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.open')}</ListItemText>
</MenuItem>
<MenuItem onClick={handleRename}>
<ListItemIcon>
<DriveFileRenameOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.rename')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.rename')}</ListItemText>
</MenuItem>
<MenuItem onClick={handleDuplicate}>
<ListItemIcon>
<ContentCopy className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.duplicate')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.duplicate')}</ListItemText>
</MenuItem>
{resume.public ? (
@ -158,27 +158,27 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
<ListItemIcon>
<LinkIcon className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.share-link')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.share-link')}</ListItemText>
</MenuItem>
) : (
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.share-link') as string}>
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.share-link')}>
<div>
<MenuItem>
<ListItemIcon>
<LinkIcon className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.share-link')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.share-link')}</ListItemText>
</MenuItem>
</div>
</Tooltip>
)}
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.delete') as string}>
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.delete')}>
<MenuItem onClick={handleDelete}>
<ListItemIcon>
<DeleteOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.delete')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.delete')}</ListItemText>
</MenuItem>
</Tooltip>
</Menu>

View File

@ -8,14 +8,14 @@ import styles from './ArrayInput.module.scss';
type Props = {
label: string;
value: string[];
value?: string[];
className?: string;
onChange: (event: any) => void;
errors?: FieldError | FieldError[];
};
const ArrayInput: React.FC<Props> = ({ value, label, onChange, errors, className }) => {
const [items, setItems] = useState<string[]>(value);
const [items, setItems] = useState<string[]>(value || []);
const onAdd = () => setItems([...items, '']);

View File

@ -56,12 +56,12 @@ const Avatar: React.FC<Props> = ({ size = 64 }) => {
<Menu anchorEl={anchorEl} onClose={handleClose} open={Boolean(anchorEl)}>
<MenuItem>
<div>
<span className="text-xs opacity-50">{t('common.avatar.menu.greeting')}</span>
<span className="text-xs opacity-50">{t<string>('common.avatar.menu.greeting')}</span>
<p>{user?.name}</p>
</div>
</MenuItem>
<Divider />
<MenuItem onClick={handleLogout}>{t('common.avatar.menu.logout')}</MenuItem>
<MenuItem onClick={handleLogout}>{t<string>('common.avatar.menu.logout')}</MenuItem>
</Menu>
</>
);

View File

@ -1,10 +1,16 @@
.content {
@apply rounded p-6 text-sm shadow lg:w-1/2 xl:w-2/5;
@apply rounded px-6 text-sm shadow lg:w-1/2 xl:w-2/5;
@apply absolute inset-4 sm:inset-x-4 sm:inset-y-auto lg:inset-auto;
@apply overflow-scroll bg-neutral-50 dark:bg-neutral-900 lg:overflow-auto;
@apply max-h-[90vh] min-h-fit;
&::-webkit-scrollbar {
display: none;
}
}
.header {
@apply sticky top-0 left-0 right-0 z-50 pt-6 bg-neutral-50 dark:bg-neutral-900;
@apply flex items-center justify-between;
@apply w-full border-b pb-5 dark:border-white/10;
@ -27,6 +33,7 @@
}
.footer {
@apply sticky bottom-0 left-0 right-0 z-50 pb-6 bg-neutral-50 dark:bg-neutral-900;
@apply flex items-center justify-end gap-x-4;
@apply w-full border-t pt-5 dark:border-white/10;
}

View File

@ -5,11 +5,12 @@ import { useRouter } from 'next/router';
import styles from './BaseModal.module.scss';
type Props = {
icon?: React.ReactNode;
isOpen: boolean;
heading: string;
handleClose: () => void;
icon?: React.ReactNode;
children?: React.ReactNode;
footerChildren?: React.ReactNode;
handleClose: () => void;
};
const BaseModal: React.FC<Props> = ({ icon, isOpen, heading, children, handleClose, footerChildren }) => {

View File

@ -10,7 +10,7 @@ const Footer: React.FC<Props> = ({ className }) => {
return (
<div className={clsx('text-xs', className)}>
<p>{t('common.footer.license')}</p>
<p>{t<string>('common.footer.license')}</p>
<p>
<Trans t={t} i18nKey="common.footer.credit">

View File

@ -72,19 +72,19 @@ const Heading: React.FC<Props> = ({
})}
>
{isEditable && (
<Tooltip title={t('builder.common.tooltip.rename-section') as string}>
<Tooltip title={t<string>('builder.common.tooltip.rename-section')}>
<IconButton onClick={toggleEditMode}>{editMode ? <Check /> : <DriveFileRenameOutline />}</IconButton>
</Tooltip>
)}
{isHideable && (
<Tooltip title={t('builder.common.tooltip.toggle-visibility') as string}>
<Tooltip title={t<string>('builder.common.tooltip.toggle-visibility')}>
<IconButton onClick={toggleVisibility}>{visibility ? <Visibility /> : <VisibilityOff />}</IconButton>
</Tooltip>
)}
{isDeletable && (
<Tooltip title={t('builder.common.tooltip.delete-section') as string}>
<Tooltip title={t<string>('builder.common.tooltip.delete-section')}>
<IconButton onClick={handleDelete}>
<Delete />
</IconButton>

View File

@ -1,70 +1,51 @@
import { Language } from '@mui/icons-material';
import { IconButton, Popover } from '@mui/material';
import { IconButton, Menu, MenuItem } from '@mui/material';
import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { MouseEvent, useState } from 'react';
import { languages } from '@/config/languages';
import { useAppDispatch } from '@/store/hooks';
import { setResumeState } from '@/store/resume/resumeSlice';
import styles from './LanguageSwitcher.module.scss';
import { TRANSLATE_URL } from '@/constants/index';
const LanguageSwitcher = () => {
const router = useRouter();
const { t } = useTranslation();
const dispatch = useAppDispatch();
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const handleClick = (event: MouseEvent<HTMLButtonElement>) => setAnchorEl(event.currentTarget);
const handleClose = () => setAnchorEl(null);
const handleChangeLanguage = (locale: string) => {
const handleChange = (locale: string) => {
const { pathname, asPath, query } = router;
handleClose();
document.cookie = `NEXT_LOCALE=${locale}; path=/; expires=2147483647`;
dispatch(setResumeState({ path: 'metadata.locale', value: locale }));
router.push({ pathname, query }, asPath, { locale });
};
const handleAddLanguage = () => window.open(TRANSLATE_URL, '_blank');
return (
<div>
<IconButton onClick={handleClick}>
<Language />
</IconButton>
<Popover
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleClose}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
>
<div className={styles.popover}>
<div className={styles.container}>
{languages.map(({ code, name, localName }) => (
<p key={code} className={styles.language} onClick={() => handleChangeLanguage(code)}>
{name} {localName && `(${localName})`}
</p>
))}
<Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleClose}>
{languages.map(({ code, name, localName }) => (
<MenuItem key={code} onClick={() => handleChange(code)}>
{name} {localName && `(${localName})`}
</MenuItem>
))}
<a href="https://translate.rxresu.me" target="_blank" rel="noreferrer" className={styles.language}>
{t('common.footer.language.missing')}
</a>
</div>
</div>
</Popover>
<MenuItem>
<span className="font-bold" onClick={handleAddLanguage}>
Add your language
</span>
</MenuItem>
</Menu>
</div>
);
};

View File

@ -66,7 +66,7 @@ const List: React.FC<Props> = ({
return (
<DndProvider backend={HTML5Backend}>
<div className={clsx(styles.container, className)}>
{isEmpty(list) && <div className={styles.empty}>{t('builder.common.list.empty-text')}</div>}
{isEmpty(list) && <div className={styles.empty}>{t<string>('builder.common.list.empty-text')}</div>}
{list.map((item, index) => {
const title = get(item, titleKey, '');
@ -76,6 +76,7 @@ const List: React.FC<Props> = ({
return (
<ListItem
key={item.id}
path={path}
item={item}
index={index}
title={title}

View File

@ -17,6 +17,7 @@ interface DragItem {
type Props = {
item: ListItemType;
path: string;
index: number;
title: string;
subtitle?: string;
@ -26,14 +27,14 @@ type Props = {
onDuplicate?: (item: ListItemType) => void;
};
const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdit, onDelete, onDuplicate }) => {
const ListItem: React.FC<Props> = ({ item, path, index, title, subtitle, onMove, onEdit, onDelete, onDuplicate }) => {
const { t } = useTranslation();
const ref = useRef<HTMLDivElement>(null);
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
const [{ handlerId }, drop] = useDrop<DragItem, any, any>({
accept: 'ListItem',
accept: path,
collect(monitor) {
return { handlerId: monitor.getHandlerId() };
},
@ -68,7 +69,7 @@ const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdi
});
const [{ isDragging }, drag] = useDrag({
type: 'ListItem',
type: path,
item: () => {
return { id: item.id, index };
},
@ -125,25 +126,25 @@ const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdi
<ListItemIcon>
<DriveFileRenameOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.common.list.actions.edit')}</ListItemText>
<ListItemText>{t<string>('builder.common.list.actions.edit')}</ListItemText>
</MenuItem>
<MenuItem onClick={() => handleDuplicate(item)}>
<ListItemIcon>
<FileCopy className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.common.list.actions.duplicate')}</ListItemText>
<ListItemText>{t<string>('builder.common.list.actions.duplicate')}</ListItemText>
</MenuItem>
<Divider />
<Tooltip arrow placement="right" title={t('builder.common.tooltip.delete-item') as string}>
<Tooltip arrow placement="right" title={t<string>('builder.common.tooltip.delete-item')}>
<div>
<MenuItem onClick={() => handleDelete(item)}>
<ListItemIcon>
<DeleteOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.common.list.actions.delete')}</ListItemText>
<ListItemText>{t<string>('builder.common.list.actions.delete')}</ListItemText>
</MenuItem>
</div>
</Tooltip>

View File

@ -1,5 +0,0 @@
import dynamic from 'next/dynamic';
const NoSSR: React.FC = ({ children }) => <>{children}</>;
export default dynamic(() => Promise.resolve(NoSSR), { ssr: false });

View File

@ -1,4 +1,7 @@
import { TextField } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers';
import dayjs from 'dayjs';
import { isEmpty } from 'lodash';
import get from 'lodash/get';
import { useEffect, useState } from 'react';
@ -8,7 +11,7 @@ import { setResumeState } from '@/store/resume/resumeSlice';
import MarkdownSupported from './MarkdownSupported';
interface Props {
type?: 'text' | 'textarea';
type?: 'text' | 'textarea' | 'date';
label: string;
path: string;
className?: string;
@ -31,6 +34,11 @@ const ResumeInput: React.FC<Props> = ({ type = 'text', label, path, className, m
dispatch(setResumeState({ path, value: event.target.value }));
};
const onChangeValue = (value: string) => {
setValue(value);
dispatch(setResumeState({ path, value }));
};
if (type === 'textarea') {
return (
<TextField
@ -45,6 +53,22 @@ const ResumeInput: React.FC<Props> = ({ type = 'text', label, path, className, m
);
}
if (type === 'date') {
return (
<DatePicker
openTo="year"
label={label}
value={value}
views={['year', 'month', 'day']}
renderInput={(params) => <TextField {...params} error={false} className={className} />}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && onChangeValue('');
date && dayjs(date).utc().isValid() && onChangeValue(dayjs(date).utc().toISOString());
}}
/>
);
}
return <TextField type={type} label={label} value={value} onChange={onChange} className={className} />;
};

View File

@ -5,55 +5,33 @@ export type Language = {
};
export const languages: Language[] = [
{
code: 'bn',
name: 'Bengali',
localName: 'বাংলা',
},
{
code: 'zh',
name: 'Chinese',
localName: '中文',
},
{
code: 'en',
name: 'English',
},
{
code: 'fr',
name: 'French',
localName: 'Français',
},
{
code: 'de',
name: 'German',
localName: 'Deutsch',
},
{
code: 'hi',
name: 'Hindi',
localName: 'हिन्दी',
},
{
code: 'it',
name: 'Italian',
localName: 'Italiano',
},
{
code: 'kn',
name: 'Kannada',
localName: 'ಕನ್ನಡ',
},
{
code: 'es',
name: 'Spanish',
localName: 'Español',
},
{
code: 'ta',
name: 'Tamil',
localName: 'தமிழ்',
},
{ code: 'ar', name: 'Arabic', localName: 'اَلْعَرَبِيَّةُ' },
{ code: 'bn', name: 'Bengali', localName: 'বাংলা' },
{ code: 'cs', name: 'Czech', localName: 'čeština' },
{ code: 'da', name: 'Danish', localName: 'Dansk' },
{ code: 'de', name: 'German', localName: 'Deutsch' },
{ code: 'el', name: 'Greek', localName: 'Ελληνικά' },
{ code: 'en', name: 'English' },
{ code: 'es', name: 'Spanish', localName: 'Español' },
{ code: 'fr', name: 'French', localName: 'Français' },
{ code: 'he', name: 'Hebrew', localName: 'Ivrit' },
{ code: 'hi', name: 'Hindi', localName: 'हिन्दी' },
{ code: 'hu', name: 'Hungarian', localName: 'Magyar' },
{ code: 'id', name: 'Indonesian', localName: 'Bahasa Indonesia' },
{ code: 'it', name: 'Italian', localName: 'Italiano' },
{ code: 'kn', name: 'Kannada', localName: 'ಕನ್ನಡ' },
{ code: 'ml', name: 'Malayalam', localName: 'മലയാളം' },
{ code: 'nl', name: 'Dutch', localName: 'Nederlands' },
{ code: 'or', name: 'Odia', localName: 'ଓଡ଼ିଆ' },
{ code: 'fa', name: 'Persian', localName: 'Farsi' },
{ code: 'pl', name: 'Polish', localName: 'Polski' },
{ code: 'pt', name: 'Portuguese', localName: 'Português' },
{ code: 'ru', name: 'Russian', localName: 'русский' },
{ code: 'sv', name: 'Swedish', localName: 'Svenska' },
{ code: 'ta', name: 'Tamil', localName: 'தமிழ்' },
{ code: 'tr', name: 'Turkish', localName: 'Türkçe' },
{ code: 'vi', name: 'Vietnamese', localName: 'Tiếng Việt' },
{ code: 'zh', name: 'Chinese', localName: '中文' },
].sort((a, b) => a.name.localeCompare(b.name));
export const languageMap: Record<string, Language> = languages.reduce(

View File

@ -0,0 +1,3 @@
import env from '@beam-australia/react-env';
export const FLAG_DISABLE_SIGNUPS = env('FLAG_DISABLE_SIGNUPS') === 'true';

View File

@ -10,6 +10,8 @@ export const FILENAME_TIMESTAMP = 'DDMMYYYYHHmmss';
// Links
export const DONATION_URL = 'https://paypal.me/RajaRajanA';
export const TRANSLATE_URL = 'https://translate.rxresu.me/';
export const DIGITALOCEAN_URL = 'https://pillai.xyz/digitalocean';
export const GITHUB_URL = 'https://github.com/AmruthPillai/Reactive-Resume';
export const PRODUCT_HUNT_URL = 'https://www.producthunt.com/posts/reactive-resume-v3';
export const GITHUB_ISSUES_URL = 'https://github.com/AmruthPillai/Reactive-Resume/issues/new/choose';

View File

@ -54,16 +54,16 @@ const ForgotPasswordModal: React.FC = () => {
<BaseModal
icon={<Password />}
isOpen={isOpen}
heading={t('modals.auth.forgot-password.heading')}
heading={t<string>('modals.auth.forgot-password.heading')}
handleClose={handleClose}
footerChildren={
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
{t('modals.auth.forgot-password.actions.send-email')}
{t<string>('modals.auth.forgot-password.actions.send-email')}
</Button>
}
>
<div className="grid gap-4">
<p>{t('modals.auth.forgot-password.body')}</p>
<p>{t<string>('modals.auth.forgot-password.body')}</p>
<form className="grid gap-4 xl:w-2/3">
<Controller
@ -72,7 +72,7 @@ const ForgotPasswordModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.auth.forgot-password.form.email.label')}
label={t<string>('modals.auth.forgot-password.form.email.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -81,7 +81,7 @@ const ForgotPasswordModal: React.FC = () => {
/>
</form>
<p className="text-xs">{t('modals.auth.forgot-password.help-text')}</p>
<p className="text-xs">{t<string>('modals.auth.forgot-password.help-text')}</p>
</div>
</BaseModal>
</>

View File

@ -3,19 +3,22 @@ import { joiResolver } from '@hookform/resolvers/joi';
import { Google, Login, Visibility, VisibilityOff } from '@mui/icons-material';
import { Button, IconButton, InputAdornment, TextField } from '@mui/material';
import Joi from 'joi';
import { isEmpty } from 'lodash';
import { Trans, useTranslation } from 'next-i18next';
import { useMemo, useState } from 'react';
import { GoogleLoginResponse, GoogleLoginResponseOffline, useGoogleLogin } from 'react-google-login';
import { Controller, useForm } from 'react-hook-form';
import toast from 'react-hot-toast';
import { useIsMutating, useMutation } from 'react-query';
import BaseModal from '@/components/shared/BaseModal';
import { FLAG_DISABLE_SIGNUPS } from '@/constants/flags';
import { login, LoginParams, loginWithGoogle, LoginWithGoogleParams } from '@/services/auth';
import { ServerError } from '@/services/axios';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
declare const google: any;
type FormData = {
identifier: string;
password: string;
@ -54,15 +57,6 @@ const LoginModal: React.FC = () => {
loginWithGoogle
);
const { signIn } = useGoogleLogin({
clientId: env('GOOGLE_CLIENT_ID'),
onSuccess: async (response: GoogleLoginResponse | GoogleLoginResponseOffline) => {
await loginWithGoogleMutation({ accessToken: (response as GoogleLoginResponse).accessToken });
handleClose();
},
});
const handleClose = () => {
dispatch(setModalState({ modal: 'auth.login', state: { open: false } }));
reset();
@ -91,8 +85,26 @@ const LoginModal: React.FC = () => {
dispatch(setModalState({ modal: 'auth.forgot', state: { open: true } }));
};
const handleLoginWithGoogle = () => {
signIn();
const handleLoginWithGoogle = async () => {
google.accounts.id.initialize({
auto_select: true,
itp_support: true,
client_id: env('GOOGLE_CLIENT_ID'),
callback: async (response: any) => {
await loginWithGoogleMutation({ credential: response.credential });
handleClose();
},
});
google.accounts.id.prompt((notification: any) => {
if (notification.isNotDisplayed() || notification.isSkippedMoment()) {
const reason = notification.getNotDisplayedReason() || notification.getSkippedReason();
toast.error(`Google returned an error while trying to sign in: ${reason}.`);
toast("Please try logging in using email/password, or use another browser that supports Google's One Tap API.");
}
});
};
const PasswordVisibility = (): React.ReactElement => {
@ -111,27 +123,29 @@ const LoginModal: React.FC = () => {
<BaseModal
icon={<Login />}
isOpen={isOpen}
heading={t('modals.auth.login.heading')}
heading={t<string>('modals.auth.login.heading')}
handleClose={handleClose}
footerChildren={
<div className="flex gap-4">
<Button
type="submit"
variant="outlined"
disabled={isLoading}
startIcon={<Google />}
onClick={handleLoginWithGoogle}
>
{t('modals.auth.login.actions.google')}
</Button>
{!isEmpty(env('GOOGLE_CLIENT_ID')) && (
<Button
type="submit"
variant="outlined"
disabled={isLoading}
startIcon={<Google />}
onClick={handleLoginWithGoogle}
>
{t<string>('modals.auth.login.actions.google')}
</Button>
)}
<Button type="submit" onClick={handleSubmit(onSubmit)} disabled={isLoading}>
{t('modals.auth.login.actions.login')}
{t<string>('modals.auth.login.actions.login')}
</Button>
</div>
}
>
<p>{t('modals.auth.login.body')}</p>
<p>{t<string>('modals.auth.login.body')}</p>
<form className="grid gap-4 xl:w-2/3">
<Controller
@ -140,9 +154,9 @@ const LoginModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.auth.login.form.username.label')}
label={t<string>('modals.auth.login.form.username.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message || t('modals.auth.login.form.username.help-text')}
helperText={fieldState.error?.message || t<string>('modals.auth.login.form.username.help-text')}
{...field}
/>
)}
@ -154,7 +168,7 @@ const LoginModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type={showPassword ? 'text' : 'password'}
label={t('modals.auth.login.form.password.label')}
label={t<string>('modals.auth.login.form.password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
InputProps={{ endAdornment: <PasswordVisibility /> }}
@ -164,11 +178,13 @@ const LoginModal: React.FC = () => {
/>
</form>
<p className="text-xs">
<Trans t={t} i18nKey="modals.auth.login.register-text">
If you don&apos;t have one, you can <a onClick={handleCreateAccount}>create an account</a> here.
</Trans>
</p>
{!FLAG_DISABLE_SIGNUPS && (
<p className="text-xs">
<Trans t={t} i18nKey="modals.auth.login.register-text">
If you don&apos;t have one, you can <a onClick={handleCreateAccount}>create an account</a> here.
</Trans>
</p>
)}
<p className="text-xs">
<Trans t={t} i18nKey="modals.auth.login.recover-text">

View File

@ -3,8 +3,8 @@ import { joiResolver } from '@hookform/resolvers/joi';
import { Google, HowToReg } from '@mui/icons-material';
import { Button, TextField } from '@mui/material';
import Joi from 'joi';
import { isEmpty } from 'lodash';
import { Trans, useTranslation } from 'next-i18next';
import { GoogleLoginResponse, GoogleLoginResponseOffline, useGoogleLogin } from 'react-google-login';
import { Controller, useForm } from 'react-hook-form';
import { useMutation } from 'react-query';
@ -14,6 +14,8 @@ import { ServerError } from '@/services/axios';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
declare const google: any;
type FormData = {
name: string;
username: string;
@ -62,15 +64,6 @@ const RegisterModal: React.FC = () => {
loginWithGoogle
);
const { signIn } = useGoogleLogin({
clientId: env('GOOGLE_CLIENT_ID'),
onSuccess: async (response: GoogleLoginResponse | GoogleLoginResponseOffline) => {
await loginWithGoogleMutation({ accessToken: (response as GoogleLoginResponse).accessToken });
handleClose();
},
});
const handleClose = () => {
dispatch(setModalState({ modal: 'auth.register', state: { open: false } }));
reset();
@ -86,35 +79,47 @@ const RegisterModal: React.FC = () => {
dispatch(setModalState({ modal: 'auth.login', state: { open: true } }));
};
const handleLoginWithGoogle = () => {
signIn();
const handleLoginWithGoogle = async () => {
google.accounts.id.initialize({
client_id: env('GOOGLE_CLIENT_ID'),
callback: async (response: any) => {
await loginWithGoogleMutation({ credential: response.credential });
handleClose();
},
auto_select: false,
});
google.accounts.id.prompt();
};
return (
<BaseModal
icon={<HowToReg />}
isOpen={isOpen}
heading={t('modals.auth.register.heading')}
heading={t<string>('modals.auth.register.heading')}
handleClose={handleClose}
footerChildren={
<>
<Button
type="submit"
variant="outlined"
disabled={isLoading}
startIcon={<Google />}
onClick={handleLoginWithGoogle}
>
{t('modals.auth.register.actions.google')}
</Button>
<div className="flex gap-4">
{!isEmpty(env('GOOGLE_CLIENT_ID')) && (
<Button
type="submit"
variant="outlined"
disabled={isLoading}
startIcon={<Google />}
onClick={handleLoginWithGoogle}
>
{t<string>('modals.auth.register.actions.google')}
</Button>
)}
<Button type="submit" onClick={handleSubmit(onSubmit)} disabled={isLoading}>
{t('modals.auth.register.actions.register')}
{t<string>('modals.auth.register.actions.register')}
</Button>
</>
</div>
}
>
<p>{t('modals.auth.register.body')}</p>
<p>{t<string>('modals.auth.register.body')}</p>
<form className="grid gap-4 md:grid-cols-2">
<Controller
@ -123,7 +128,7 @@ const RegisterModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.auth.register.form.name.label')}
label={t<string>('modals.auth.register.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -136,7 +141,7 @@ const RegisterModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('modals.auth.register.form.username.label')}
label={t<string>('modals.auth.register.form.username.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -150,7 +155,7 @@ const RegisterModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type="email"
label={t('modals.auth.register.form.email.label')}
label={t<string>('modals.auth.register.form.email.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -165,7 +170,7 @@ const RegisterModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type="password"
label={t('modals.auth.register.form.password.label')}
label={t<string>('modals.auth.register.form.password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -179,7 +184,7 @@ const RegisterModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type="password"
label={t('modals.auth.register.form.confirm-password.label')}
label={t<string>('modals.auth.register.form.confirm-password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -65,15 +65,15 @@ const ResetPasswordModal: React.FC = () => {
<BaseModal
icon={<LockReset />}
isOpen={isOpen}
heading={t('modals.auth.reset-password.heading')}
heading={t<string>('modals.auth.reset-password.heading')}
handleClose={handleClose}
footerChildren={
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
{t('modals.auth.reset-password.actions.set-password')}
{t<string>('modals.auth.reset-password.actions.set-password')}
</Button>
}
>
<p>{t('modals.auth.reset-password.body')}</p>
<p>{t<string>('modals.auth.reset-password.body')}</p>
<form className="grid gap-4 md:grid-cols-2">
<Controller
@ -83,7 +83,7 @@ const ResetPasswordModal: React.FC = () => {
<TextField
autoFocus
type="password"
label={t('modals.auth.reset-password.form.password.label')}
label={t<string>('modals.auth.reset-password.form.password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -97,7 +97,7 @@ const ResetPasswordModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type="password"
label={t('modals.auth.reset-password.form.confirm-password.label')}
label={t<string>('modals.auth.reset-password.form.confirm-password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -1,7 +1,7 @@
import { joiResolver } from '@hookform/resolvers/joi';
import { Add, DriveFileRenameOutline } from '@mui/icons-material';
import DatePicker from '@mui/lab/DatePicker';
import { Button, TextField } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers';
import { Award, SectionPath } from '@reactive-resume/schema';
import dayjs from 'dayjs';
import Joi from 'joi';
@ -50,8 +50,8 @@ const AwardModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -101,7 +101,7 @@ const AwardModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.title.label')}
label={t<string>('builder.common.form.title.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -115,7 +115,7 @@ const AwardModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.awards.form.awarder.label')}
label={t<string>('builder.leftSidebar.sections.awards.form.awarder.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -130,11 +130,11 @@ const AwardModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.date.label')}
label={t<string>('builder.common.form.date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -152,7 +152,7 @@ const AwardModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -169,7 +169,7 @@ const AwardModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -1,7 +1,7 @@
import { joiResolver } from '@hookform/resolvers/joi';
import { Add, DriveFileRenameOutline } from '@mui/icons-material';
import DatePicker from '@mui/lab/DatePicker';
import { Button, TextField } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers';
import { Certificate, SectionPath } from '@reactive-resume/schema';
import dayjs from 'dayjs';
import Joi from 'joi';
@ -50,8 +50,8 @@ const CertificateModal: React.FC = () => {
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -101,7 +101,7 @@ const CertificateModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -115,7 +115,7 @@ const CertificateModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.certifications.form.issuer.label')}
label={t<string>('builder.leftSidebar.sections.certifications.form.issuer.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -130,11 +130,11 @@ const CertificateModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.date.label')}
label={t<string>('builder.common.form.date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -152,7 +152,7 @@ const CertificateModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -169,7 +169,7 @@ const CertificateModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -1,7 +1,7 @@
import { joiResolver } from '@hookform/resolvers/joi';
import { Add, DriveFileRenameOutline } from '@mui/icons-material';
import DatePicker from '@mui/lab/DatePicker';
import { Button, Slider, TextField } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers';
import { Custom } from '@reactive-resume/schema';
import dayjs from 'dayjs';
import Joi from 'joi';
@ -67,8 +67,8 @@ const CustomModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -118,7 +118,7 @@ const CustomModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.title.label')}
label={t<string>('builder.common.form.title.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -131,7 +131,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.subtitle.label')}
label={t<string>('builder.common.form.subtitle.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -146,11 +146,11 @@ const CustomModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -170,11 +170,11 @@ const CustomModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -192,7 +192,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -207,7 +207,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.level.label')}
label={t<string>('builder.common.form.level.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -221,7 +221,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field }) => (
<div className="col-span-2">
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
<h4 className="mb-3 font-semibold">{t<string>('builder.common.form.levelNum.label')}</h4>
<div className="px-10">
<Slider
@ -245,7 +245,7 @@ const CustomModal: React.FC = () => {
defaultValue={0}
color="secondary"
valueLabelDisplay="auto"
aria-label={t('builder.common.form.levelNum.label')}
aria-label={t<string>('builder.common.form.levelNum.label')}
/>
</div>
</div>
@ -260,7 +260,7 @@ const CustomModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}
@ -274,7 +274,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.common.form.keywords.label')}
label={t<string>('builder.common.form.keywords.label')}
value={field.value as string[]}
onChange={field.onChange}
errors={fieldState.error}

View File

@ -1,7 +1,7 @@
import { joiResolver } from '@hookform/resolvers/joi';
import { Add, DriveFileRenameOutline } from '@mui/icons-material';
import DatePicker from '@mui/lab/DatePicker';
import { Button, TextField } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers';
import { Education, SectionPath } from '@reactive-resume/schema';
import dayjs from 'dayjs';
import Joi from 'joi';
@ -63,8 +63,8 @@ const EducationModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -114,7 +114,7 @@ const EducationModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.leftSidebar.sections.education.form.institution.label')}
label={t<string>('builder.leftSidebar.sections.education.form.institution.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -128,7 +128,7 @@ const EducationModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.education.form.degree.label')}
label={t<string>('builder.leftSidebar.sections.education.form.degree.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -141,7 +141,7 @@ const EducationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.leftSidebar.sections.education.form.area-study.label')}
label={t<string>('builder.leftSidebar.sections.education.form.area-study.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -154,7 +154,7 @@ const EducationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.leftSidebar.sections.education.form.grade.label')}
label={t<string>('builder.leftSidebar.sections.education.form.grade.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -169,11 +169,11 @@ const EducationModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -193,17 +193,17 @@ const EducationModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
{...params}
error={!!fieldState.error}
helperText={fieldState.error?.message || t('builder.common.form.end-date.help-text')}
helperText={fieldState.error?.message || t<string>('builder.common.form.end-date.help-text')}
/>
)}
/>
@ -215,7 +215,7 @@ const EducationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -233,7 +233,7 @@ const EducationModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}
@ -247,7 +247,7 @@ const EducationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.leftSidebar.sections.education.form.courses.label')}
label={t<string>('builder.leftSidebar.sections.education.form.courses.label')}
value={field.value as string[]}
onChange={field.onChange}
errors={fieldState.error}

View File

@ -41,8 +41,8 @@ const InterestModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -92,7 +92,7 @@ const InterestModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -106,7 +106,7 @@ const InterestModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.common.form.keywords.label')}
label={t<string>('builder.common.form.keywords.label')}
value={field.value as string[]}
onChange={field.onChange}
errors={fieldState.error}

View File

@ -42,8 +42,8 @@ const LanguageModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -93,7 +93,7 @@ const LanguageModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -107,7 +107,7 @@ const LanguageModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.common.form.level.label')}
label={t<string>('builder.common.form.level.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -120,7 +120,7 @@ const LanguageModal: React.FC = () => {
control={control}
render={({ field }) => (
<div className="col-span-2">
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
<h4 className="mb-3 font-semibold">{t<string>('builder.common.form.levelNum.label')}</h4>
<div className="px-10">
<Slider
@ -144,7 +144,7 @@ const LanguageModal: React.FC = () => {
defaultValue={0}
color="secondary"
valueLabelDisplay="auto"
aria-label={t('builder.common.form.levelNum.label')}
aria-label={t<string>('builder.common.form.levelNum.label')}
/>
</div>
</div>

View File

@ -42,11 +42,11 @@ const ProfileModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = t('builder.common.actions.add', {
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
const addText = t<string>('builder.common.actions.add', {
token: t<string>('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
});
const editText = t('builder.common.actions.edit', {
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
const editText = t<string>('builder.common.actions.edit', {
token: t<string>('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
});
const { reset, control, handleSubmit } = useForm<FormData>({
@ -97,7 +97,7 @@ const ProfileModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.leftSidebar.sections.profiles.form.network.label')}
label={t<string>('builder.leftSidebar.sections.profiles.form.network.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -111,7 +111,7 @@ const ProfileModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.profiles.form.username.label')}
label={t<string>('builder.leftSidebar.sections.profiles.form.username.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
InputProps={{
@ -127,7 +127,7 @@ const ProfileModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
className="col-span-2"
placeholder="https://"
error={!!fieldState.error}

View File

@ -1,7 +1,7 @@
import { joiResolver } from '@hookform/resolvers/joi';
import { Add, DriveFileRenameOutline } from '@mui/icons-material';
import DatePicker from '@mui/lab/DatePicker';
import { Button, TextField } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers';
import { Project, SectionPath } from '@reactive-resume/schema';
import dayjs from 'dayjs';
import Joi from 'joi';
@ -59,8 +59,8 @@ const ProjectModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -110,7 +110,7 @@ const ProjectModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -124,7 +124,7 @@ const ProjectModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.common.form.description.label')}
label={t<string>('builder.common.form.description.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -139,11 +139,11 @@ const ProjectModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -163,11 +163,11 @@ const ProjectModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -185,7 +185,7 @@ const ProjectModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -203,7 +203,7 @@ const ProjectModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}
@ -217,7 +217,7 @@ const ProjectModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.common.form.keywords.label')}
label={t<string>('builder.common.form.keywords.label')}
value={field.value as string[]}
onChange={field.onChange}
errors={fieldState.error}

View File

@ -1,7 +1,7 @@
import { joiResolver } from '@hookform/resolvers/joi';
import { Add, DriveFileRenameOutline } from '@mui/icons-material';
import DatePicker from '@mui/lab/DatePicker';
import { Button, TextField } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers';
import { Publication, SectionPath } from '@reactive-resume/schema';
import dayjs from 'dayjs';
import Joi from 'joi';
@ -50,8 +50,8 @@ const PublicationModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -101,7 +101,7 @@ const PublicationModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -115,7 +115,7 @@ const PublicationModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label="{t('builder.leftSidebar.sections.publications.form.publisher.label')}"
label={t<string>('builder.leftSidebar.sections.publications.form.publisher.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -130,11 +130,11 @@ const PublicationModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.date.label')}
label={t<string>('builder.common.form.date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -152,7 +152,7 @@ const PublicationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -169,7 +169,7 @@ const PublicationModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -47,8 +47,8 @@ const ReferenceModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -98,7 +98,7 @@ const ReferenceModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -112,7 +112,7 @@ const ReferenceModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.references.form.relationship.label')}
label={t<string>('builder.leftSidebar.sections.references.form.relationship.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -125,7 +125,7 @@ const ReferenceModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.phone.label')}
label={t<string>('builder.common.form.phone.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -138,7 +138,7 @@ const ReferenceModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.email.label')}
label={t<string>('builder.common.form.email.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -154,7 +154,7 @@ const ReferenceModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -45,8 +45,8 @@ const SkillModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -96,7 +96,7 @@ const SkillModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -109,7 +109,7 @@ const SkillModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.level.label')}
label={t<string>('builder.common.form.level.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -122,7 +122,7 @@ const SkillModal: React.FC = () => {
control={control}
render={({ field }) => (
<div className="col-span-2">
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
<h4 className="mb-3 font-semibold">{t<string>('builder.common.form.levelNum.label')}</h4>
<div className="px-3">
<Slider
@ -146,7 +146,7 @@ const SkillModal: React.FC = () => {
defaultValue={0}
color="secondary"
valueLabelDisplay="auto"
aria-label={t('builder.common.form.levelNum.label')}
aria-label={t<string>('builder.common.form.levelNum.label')}
/>
</div>
</div>
@ -158,8 +158,8 @@ const SkillModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.common.form.keywords.label')}
value={field.value as string[]}
label={t<string>('builder.common.form.keywords.label')}
value={field.value}
onChange={field.onChange}
errors={fieldState.error}
className="col-span-2"

View File

@ -1,7 +1,7 @@
import { joiResolver } from '@hookform/resolvers/joi';
import { Add, DriveFileRenameOutline } from '@mui/icons-material';
import DatePicker from '@mui/lab/DatePicker';
import { Button, TextField } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers';
import { SectionPath, Volunteer } from '@reactive-resume/schema';
import dayjs from 'dayjs';
import Joi from 'joi';
@ -56,8 +56,8 @@ const VolunteerModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -107,7 +107,7 @@ const VolunteerModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.leftSidebar.sections.volunteer.form.organization.label')}
label={t<string>('builder.leftSidebar.sections.volunteer.form.organization.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -121,7 +121,7 @@ const VolunteerModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.common.form.position.label')}
label={t<string>('builder.common.form.position.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -136,11 +136,11 @@ const VolunteerModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -160,11 +160,11 @@ const VolunteerModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -182,7 +182,7 @@ const VolunteerModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -200,7 +200,7 @@ const VolunteerModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -1,7 +1,7 @@
import { joiResolver } from '@hookform/resolvers/joi';
import { Add, DriveFileRenameOutline } from '@mui/icons-material';
import DatePicker from '@mui/lab/DatePicker';
import { Button, TextField } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers';
import { SectionPath, WorkExperience } from '@reactive-resume/schema';
import dayjs from 'dayjs';
import Joi from 'joi';
@ -56,8 +56,8 @@ const WorkModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -107,7 +107,7 @@ const WorkModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -121,7 +121,7 @@ const WorkModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.common.form.position.label')}
label={t<string>('builder.common.form.position.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -136,11 +136,11 @@ const WorkModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
@ -160,17 +160,17 @@ const WorkModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
date && dayjs(date).isValid() && field.onChange(date.toISOString());
date && dayjs(date).utc().isValid() && field.onChange(dayjs(date).utc().toISOString());
}}
renderInput={(params) => (
<TextField
{...params}
error={!!fieldState.error}
helperText={fieldState.error?.message || t('builder.common.form.end-date.help-text')}
helperText={fieldState.error?.message || t<string>('builder.common.form.end-date.help-text')}
/>
)}
/>
@ -182,7 +182,7 @@ const WorkModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -200,7 +200,7 @@ const WorkModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -58,7 +58,7 @@ const CreateResumeModal: React.FC = () => {
const slug = name
? name
.toLowerCase()
.replace(/[`~!@#$%^&*()_|+=?;:'",.<>{}[]\\\/]/gi, '')
.replace(/[^\w\s]/gi, '')
.replace(/[ ]/gi, '-')
: '';
@ -85,15 +85,15 @@ const CreateResumeModal: React.FC = () => {
<BaseModal
isOpen={isOpen}
icon={<Add />}
heading={t('modals.dashboard.create-resume.heading')}
heading={t<string>('modals.dashboard.create-resume.heading')}
handleClose={handleClose}
footerChildren={
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
{t('modals.dashboard.create-resume.actions.create-resume')}
{t<string>('modals.dashboard.create-resume.actions.create-resume')}
</Button>
}
>
<p>{t('modals.dashboard.create-resume.body')}</p>
<p>{t<string>('modals.dashboard.create-resume.body')}</p>
<form className="grid gap-4">
<Controller
@ -102,7 +102,7 @@ const CreateResumeModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.dashboard.create-resume.form.name.label')}
label={t<string>('modals.dashboard.create-resume.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -115,7 +115,7 @@ const CreateResumeModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('modals.dashboard.create-resume.form.slug.label')}
label={t<string>('modals.dashboard.create-resume.form.slug.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -125,7 +125,7 @@ const CreateResumeModal: React.FC = () => {
<FormGroup>
<FormControlLabel
label={t('modals.dashboard.create-resume.form.public.label') as string}
label={t<string>('modals.dashboard.create-resume.form.public.label')}
control={
<Controller
name="isPublic"

View File

@ -63,7 +63,7 @@ const ImportExternalModal: React.FC = () => {
const file = event.target.files[0];
if (file.size > FILE_UPLOAD_MAX_SIZE) {
toast.error(t('common.toast.error.upload-file-size'));
toast.error(t<string>('common.toast.error.upload-file-size'));
return;
}
@ -78,13 +78,13 @@ const ImportExternalModal: React.FC = () => {
<BaseModal
isOpen={isOpen}
icon={<ImportExport />}
heading={t('modals.dashboard.import-external.heading')}
heading={t<string>('modals.dashboard.import-external.heading')}
handleClose={handleClose}
>
<div className="grid gap-5">
<h2 className="inline-flex items-center gap-2 text-lg font-medium">
<LinkedIn />
{t('modals.dashboard.import-external.linkedin.heading')}
{t<string>('modals.dashboard.import-external.linkedin.heading')}
</h2>
<p className="mb-2">
@ -110,7 +110,7 @@ const ImportExternalModal: React.FC = () => {
startIcon={<UploadFile />}
onClick={() => handleClick('linkedin')}
>
{t('modals.dashboard.import-external.linkedin.actions.upload-archive')}
{t<string>('modals.dashboard.import-external.linkedin.actions.upload-archive')}
</Button>
<input
@ -128,7 +128,7 @@ const ImportExternalModal: React.FC = () => {
<div className="grid gap-5">
<h2 className="inline-flex items-center gap-2 text-lg font-medium">
<Code />
{t('modals.dashboard.import-external.json-resume.heading')}
{t<string>('modals.dashboard.import-external.json-resume.heading')}
</h2>
<p className="mb-2">
@ -154,7 +154,7 @@ const ImportExternalModal: React.FC = () => {
startIcon={<UploadFile />}
onClick={() => handleClick('json-resume')}
>
{t('modals.dashboard.import-external.json-resume.actions.upload-json')}
{t<string>('modals.dashboard.import-external.json-resume.actions.upload-json')}
</Button>
<input
@ -172,10 +172,10 @@ const ImportExternalModal: React.FC = () => {
<div className="grid gap-5">
<h2 className="inline-flex items-center gap-2 text-lg font-medium">
<TrackChanges />
{t('modals.dashboard.import-external.reactive-resume.heading')}
{t<string>('modals.dashboard.import-external.reactive-resume.heading')}
</h2>
<p className="mb-2">{t('modals.dashboard.import-external.reactive-resume.body')}</p>
<p className="mb-2">{t<string>('modals.dashboard.import-external.reactive-resume.body')}</p>
<div className="flex gap-4">
<Button
@ -184,7 +184,7 @@ const ImportExternalModal: React.FC = () => {
startIcon={<UploadFile />}
onClick={() => handleClick('reactive-resume')}
>
{t('modals.dashboard.import-external.reactive-resume.actions.upload-json')}
{t<string>('modals.dashboard.import-external.reactive-resume.actions.upload-json')}
</Button>
<Button
@ -193,7 +193,7 @@ const ImportExternalModal: React.FC = () => {
startIcon={<UploadFile />}
onClick={() => handleClick('reactive-resume-v2')}
>
{t('modals.dashboard.import-external.reactive-resume.actions.upload-json-v2')}
{t<string>('modals.dashboard.import-external.reactive-resume.actions.upload-json-v2')}
</Button>
<input

View File

@ -56,7 +56,7 @@ const RenameResumeModal: React.FC = () => {
const slug = name
? name
.toLowerCase()
.replace(/[`~!@#$%^&*()_|+=?;:'",.<>{}[]\\\/]/gi, '')
.replace(/[^\w\s]/gi, '')
.replace(/[ ]/gi, '-')
: '';
@ -92,11 +92,11 @@ const RenameResumeModal: React.FC = () => {
<BaseModal
icon={<DriveFileRenameOutline />}
isOpen={isOpen}
heading={t('modals.dashboard.rename-resume.heading')}
heading={t<string>('modals.dashboard.rename-resume.heading')}
handleClose={handleClose}
footerChildren={
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
{t('modals.dashboard.rename-resume.actions.rename-resume')}
{t<string>('modals.dashboard.rename-resume.actions.rename-resume')}
</Button>
}
>
@ -107,7 +107,7 @@ const RenameResumeModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.dashboard.rename-resume.form.name.label')}
label={t<string>('modals.dashboard.rename-resume.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -120,7 +120,7 @@ const RenameResumeModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('modals.dashboard.rename-resume.form.slug.label')}
label={t<string>('modals.dashboard.rename-resume.form.slug.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -3,7 +3,35 @@ const path = require('path');
const i18nConfig = {
i18n: {
defaultLocale: 'en',
locales: ['bn', 'de', 'en', 'es', 'fr', 'hi', 'it', 'kn', 'ta', 'zh'],
locales: [
'ar',
'bn',
'cs',
'da',
'de',
'el',
'en',
'es',
'fa',
'fr',
'he',
'hi',
'hu',
'id',
'it',
'kn',
'ml',
'nl',
'or',
'pl',
'pt',
'ru',
'sv',
'ta',
'tr',
'vi',
'zh',
],
},
nsSeparator: '.',
localePath: path.resolve('./public/locales'),

View File

@ -12,7 +12,7 @@ const nextConfig = {
},
images: {
domains: ['www.gravatar.com'],
domains: ['cdn.rxresu.me', 'www.gravatar.com'],
},
async rewrites() {

View File

@ -9,70 +9,74 @@
},
"dependencies": {
"@beam-australia/react-env": "^3.1.1",
"@emotion/css": "^11.7.1",
"@emotion/react": "^11.8.2",
"@emotion/styled": "^11.8.1",
"@hookform/resolvers": "2.8.8",
"@monaco-editor/react": "^4.3.1",
"@mui/icons-material": "^5.5.0",
"@mui/lab": "^5.0.0-alpha.72",
"@mui/material": "^5.5.0",
"@reduxjs/toolkit": "^1.8.0",
"axios": "^0.26.1",
"clsx": "^1.1.1",
"dayjs": "^1.10.8",
"@date-io/dayjs": "^2.14.0",
"@emotion/css": "^11.9.0",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@hookform/resolvers": "2.9.7",
"@monaco-editor/react": "^4.4.5",
"@mui/icons-material": "^5.8.4",
"@mui/lab": "^5.0.0-alpha.92",
"@mui/material": "^5.9.2",
"@mui/system": "^5.9.2",
"@mui/x-date-pickers": "5.0.0-beta.3",
"@next/env": "^12.2.3",
"@reduxjs/toolkit": "^1.8.3",
"axios": "^0.27.2",
"clsx": "^1.2.1",
"dayjs": "^1.11.4",
"downloadjs": "^1.4.7",
"joi": "^17.6.0",
"lodash": "^4.17.21",
"md5-hex": "^4.0.0",
"monaco-editor": "^0.33.0",
"nanoid": "^3.3.1",
"next": "12.1.0",
"next-i18next": "^10.5.0",
"react": ">=17",
"nanoid": "^3.3.4",
"next": "12.2.3",
"next-i18next": "^11.3.0",
"react": "18.2.0",
"react-beautiful-dnd": "^13.1.0",
"react-colorful": "^5.5.1",
"react-dnd": "^15.1.1",
"react-dnd-html5-backend": "^15.1.2",
"react-dom": ">=17",
"react-google-login": "^5.2.2",
"react-hook-form": "^7.28.0",
"react-hot-toast": "2.2.0",
"react-hotkeys-hook": "^3.4.4",
"react-icons": "^4.3.1",
"react-markdown": "^8.0.0",
"react-query": "^3.34.16",
"react-redux": "^7.2.6",
"react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1",
"react-dom": "18.2.0",
"react-hook-form": "^7.34.0",
"react-hot-toast": "2.3.0",
"react-hotkeys-hook": "^3.4.7",
"react-icons": "^4.4.0",
"react-markdown": "^8.0.3",
"react-query": "^3.39.2",
"react-redux": "^8.0.2",
"react-zoom-pan-pinch": "^2.1.3",
"redux": "^4.1.2",
"redux": "^4.2.0",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",
"remark-gfm": "^3.0.1",
"sharp": "^0.30.2",
"sharp": "^0.30.7",
"uuid": "^8.3.2",
"webfontloader": "^1.6.28"
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@babel/core": "^7.18.9",
"@reactive-resume/schema": "workspace:*",
"@tailwindcss/typography": "^0.5.2",
"@tailwindcss/typography": "^0.5.4",
"@types/downloadjs": "^1.4.3",
"@types/lodash": "^4.14.179",
"@types/node": "17.0.21",
"@types/react": "17.0.40",
"@types/lodash": "^4.14.182",
"@types/node": "18.6.2",
"@types/react": "18.0.15",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-redux": "^7.1.23",
"@types/tailwindcss": "^3.0.9",
"@types/react-redux": "^7.1.24",
"@types/tailwindcss": "^3.0.11",
"@types/uuid": "^8.3.4",
"@types/webfontloader": "^1.6.34",
"autoprefixer": "^10.4.2",
"eslint": "^8.11.0",
"eslint-config-next": "12.1.0",
"next-sitemap": "^2.5.7",
"postcss": "^8.4.8",
"prettier": "^2.5.1",
"sass": "^1.49.9",
"tailwindcss": "^3.0.23",
"typescript": "<4.6.0"
"autoprefixer": "^10.4.8",
"csstype": "^3.1.0",
"eslint": "^8.20.0",
"eslint-config-next": "12.2.3",
"next-sitemap": "^3.1.15",
"postcss": "^8.4.14",
"prettier": "^2.7.1",
"sass": "^1.54.0",
"tailwindcss": "^3.1.7",
"typescript": "^4.7.4"
}
}

View File

@ -62,7 +62,7 @@ const Build: NextPage<Props> = ({ username, slug }) => {
<div className={styles.container}>
<Head>
<title>
{resume.name} | {t('common.title')}
{resume.name} | {t<string>('common.title')}
</title>
</Head>

View File

@ -59,6 +59,14 @@ const Preview: NextPage<Props> = ({ username, slug, resume: initialData }) => {
}
}, [dispatch, initialData]);
useEffect(() => {
if (!isEmpty(resume) && router.locale !== resume.metadata.locale) {
const { pathname, asPath, query } = router;
router.push({ pathname, query }, asPath, { locale: resume.metadata.locale });
}
}, [resume, router]);
useQuery<Resume>(`resume/${username}/${slug}`, () => fetchResumeByIdentifier({ username, slug }), {
initialData,
retry: false,

View File

@ -3,6 +3,7 @@ import clsx from 'clsx';
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import { GetServerSideProps, NextPage } from 'next';
import { useRouter } from 'next/router';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { useEffect } from 'react';
@ -20,6 +21,7 @@ type QueryParams = {
type Props = {
resume?: Resume;
locale: string;
redirect?: any;
};
@ -35,7 +37,13 @@ export const getServerSideProps: GetServerSideProps<Props | Promise<Props>, Quer
const resume = await fetchResumeByIdentifier({ username, slug, options: { secretKey } });
const displayLocale = resume.metadata.locale || locale || 'en';
return { props: { resume, ...(await serverSideTranslations(displayLocale, ['common'])) } };
return {
props: {
resume,
locale: displayLocale,
...(await serverSideTranslations(displayLocale, ['common'])),
},
};
} catch (error) {
return {
redirect: {
@ -46,7 +54,9 @@ export const getServerSideProps: GetServerSideProps<Props | Promise<Props>, Quer
}
};
const Printer: NextPage<Props> = ({ resume: initialData }) => {
const Printer: NextPage<Props> = ({ resume: initialData, locale }) => {
const router = useRouter();
const dispatch = useAppDispatch();
const resume = useAppSelector((state) => state.resume);
@ -55,6 +65,12 @@ const Printer: NextPage<Props> = ({ resume: initialData }) => {
if (initialData) dispatch(setResume(initialData));
}, [dispatch, initialData]);
useEffect(() => {
const { pathname, asPath, query } = router;
router.push({ pathname, query }, asPath, { locale });
}, [router, locale]);
if (!resume || isEmpty(resume)) return null;
const layout: string[][][] = get(resume, 'metadata.layout', []);

View File

@ -1,9 +1,10 @@
import '@/styles/globals.scss';
import DateAdapter from '@mui/lab/AdapterDayjs';
import LocalizationProvider from '@mui/lab/LocalizationProvider';
import DayjsAdapter from '@date-io/dayjs';
import { LocalizationProvider } from '@mui/x-date-pickers';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import Script from 'next/script';
import { appWithTranslation } from 'next-i18next';
import { Toaster } from 'react-hot-toast';
import { QueryClientProvider } from 'react-query';
@ -31,7 +32,7 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
</Head>
<ReduxProvider store={store}>
<LocalizationProvider dateAdapter={DateAdapter}>
<LocalizationProvider dateAdapter={DayjsAdapter}>
<PersistGate loading={null} persistor={persistor}>
<QueryClientProvider client={queryClient}>
<WrapperRegistry>
@ -52,6 +53,8 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
</PersistGate>
</LocalizationProvider>
</ReduxProvider>
<Script src="https://accounts.google.com/gsi/client" async defer />
</>
);
};

View File

@ -4,6 +4,7 @@ import NextDocument, { DocumentContext, Head, Html, Main, NextScript } from 'nex
const Document: NextPage = () => (
<Html>
<Head />
<body>
<Main />
<NextScript />

View File

@ -33,7 +33,7 @@ const Dashboard: NextPage = () => {
<div className={styles.container}>
<Head>
<title>
{t('dashboard.title')} | {t('common.title')}
{t<string>('dashboard.title')} | {t<string>('common.title')}
</title>
</Head>
@ -51,15 +51,15 @@ const Dashboard: NextPage = () => {
<ResumeCard
modal="dashboard.create-resume"
icon={Add}
title={t('dashboard.create-resume.title')}
subtitle={t('dashboard.create-resume.subtitle')}
title={t<string>('dashboard.create-resume.title')}
subtitle={t<string>('dashboard.create-resume.subtitle')}
/>
<ResumeCard
modal="dashboard.import-external"
icon={ImportExport}
title={t('dashboard.import-external.title')}
subtitle={t('dashboard.import-external.subtitle')}
title={t<string>('dashboard.import-external.title')}
subtitle={t<string>('dashboard.import-external.subtitle')}
/>
{data.map((resume) => (

View File

@ -1,6 +1,6 @@
import { Link as LinkIcon } from '@mui/icons-material';
import { DarkMode, LightMode, Link as LinkIcon } from '@mui/icons-material';
import { Masonry } from '@mui/lab';
import { Button } from '@mui/material';
import { Button, IconButton, NoSsr } from '@mui/material';
import type { GetStaticProps, NextPage } from 'next';
import Image from 'next/image';
import Link from 'next/link';
@ -11,15 +11,16 @@ import Testimony from '@/components/landing/Testimony';
import Footer from '@/components/shared/Footer';
import LanguageSwitcher from '@/components/shared/LanguageSwitcher';
import Logo from '@/components/shared/Logo';
import NoSSR from '@/components/shared/NoSSR';
import { screenshots } from '@/config/screenshots';
import { FLAG_DISABLE_SIGNUPS } from '@/constants/flags';
import testimonials from '@/data/testimonials';
import { logout } from '@/store/auth/authSlice';
import { setTheme } from '@/store/build/buildSlice';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import styles from '@/styles/pages/Home.module.scss';
import { DONATION_URL, GITHUB_URL } from '../constants';
import { DIGITALOCEAN_URL, DONATION_URL, GITHUB_URL } from '../constants';
export const getStaticProps: GetStaticProps = async ({ locale = 'en' }) => {
return {
@ -34,12 +35,15 @@ const Home: NextPage = () => {
const dispatch = useAppDispatch();
const theme = useAppSelector((state) => state.build.theme);
const isLoggedIn = useAppSelector((state) => state.auth.isLoggedIn);
const handleLogin = () => dispatch(setModalState({ modal: 'auth.login', state: { open: true } }));
const handleRegister = () => dispatch(setModalState({ modal: 'auth.register', state: { open: true } }));
const handleToggle = () => dispatch(setTheme({ theme: theme === 'light' ? 'dark' : 'light' }));
const handleLogout = () => dispatch(logout());
return (
@ -50,52 +54,52 @@ const Home: NextPage = () => {
</div>
<div className={styles.main}>
<h1>{t('common.title')}</h1>
<h1>{t<string>('common.title')}</h1>
<h2>{t('common.subtitle')}</h2>
<h2>{t<string>('common.subtitle')}</h2>
<NoSSR>
<NoSsr>
<div className={styles.buttonWrapper}>
{isLoggedIn ? (
<>
<Link href="/dashboard" passHref>
<Button>{t('landing.actions.app')}</Button>
<Button>{t<string>('landing.actions.app')}</Button>
</Link>
<Button variant="outlined" onClick={handleLogout}>
{t('landing.actions.logout')}
{t<string>('landing.actions.logout')}
</Button>
</>
) : (
<>
<Button onClick={handleLogin}>{t('landing.actions.login')}</Button>
<Button onClick={handleLogin}>{t<string>('landing.actions.login')}</Button>
<Button variant="outlined" onClick={handleRegister}>
{t('landing.actions.register')}
<Button variant="outlined" onClick={handleRegister} disabled={FLAG_DISABLE_SIGNUPS}>
{t<string>('landing.actions.register')}
</Button>
</>
)}
</div>
</NoSSR>
</NoSsr>
</div>
</div>
<section className={styles.section}>
<h6>{t('landing.summary.heading')}</h6>
<h6>{t<string>('landing.summary.heading')}</h6>
<p>{t('landing.summary.body')}</p>
<p>{t<string>('landing.summary.body')}</p>
</section>
<section className={styles.section}>
<h6>{t('landing.features.heading')}</h6>
<h6>{t<string>('landing.features.heading')}</h6>
<ul className="list-inside list-disc leading-loose">
<li>{t('landing.features.list.free')}</li>
<li>{t('landing.features.list.ads')}</li>
<li>{t('landing.features.list.tracking')}</li>
<li>{t('landing.features.list.languages')}</li>
<li>{t('landing.features.list.import')}</li>
<li>{t('landing.features.list.export')}</li>
<li>{t<string>('landing.features.list.free')}</li>
<li>{t<string>('landing.features.list.ads')}</li>
<li>{t<string>('landing.features.list.tracking')}</li>
<li>{t<string>('landing.features.list.languages')}</li>
<li>{t<string>('landing.features.list.import')}</li>
<li>{t<string>('landing.features.list.export')}</li>
<li>
<Trans t={t} i18nKey="landing.features.list.more">
And a lot of exciting features,
@ -108,7 +112,7 @@ const Home: NextPage = () => {
</section>
<section className={styles.section}>
<h6>{t('landing.screenshots.heading')}</h6>
<h6>{t<string>('landing.screenshots.heading')}</h6>
<div className={styles.screenshots}>
{screenshots.map(({ src, alt }) => (
@ -120,7 +124,7 @@ const Home: NextPage = () => {
</section>
<section className={styles.section}>
<h6>{t('landing.testimonials.heading')}</h6>
<h6>{t<string>('landing.testimonials.heading')}</h6>
<p className="my-3">
<Trans t={t} i18nKey="landing.testimonials.body">
@ -145,37 +149,37 @@ const Home: NextPage = () => {
</section>
<section className={styles.section}>
<h6>{t('landing.links.heading')}</h6>
<h6>{t<string>('landing.links.heading')}</h6>
<div>
<Link href="/meta/privacy" passHref>
<Button variant="text" startIcon={<LinkIcon />}>
{t('landing.links.links.privacy')}
{t<string>('landing.links.links.privacy')}
</Button>
</Link>
<Link href="/meta/service" passHref>
<Button variant="text" startIcon={<LinkIcon />}>
{t('landing.links.links.service')}
{t<string>('landing.links.links.service')}
</Button>
</Link>
<a href={GITHUB_URL} target="_blank" rel="noreferrer">
<Button variant="text" startIcon={<LinkIcon />}>
{t('landing.links.links.github')}
{t<string>('landing.links.links.github')}
</Button>
</a>
<a href={DONATION_URL} target="_blank" rel="noreferrer">
<Button variant="text" startIcon={<LinkIcon />}>
{t('landing.links.links.donate')}
{t<string>('landing.links.links.donate')}
</Button>
</a>
</div>
</section>
<section className={styles.section}>
<a href="https://pillai.xyz/digitalocean" target="_blank" rel="noreferrer">
<a href={DIGITALOCEAN_URL} target="_blank" rel="noreferrer">
<Image src="/images/sponsors/digitalocean.svg" alt="Powered By DigitalOcean" width={200} height={40} />
</a>
</section>
@ -187,7 +191,11 @@ const Home: NextPage = () => {
<div>v{process.env.appVersion}</div>
</div>
<LanguageSwitcher />
<div className={styles.actions}>
<IconButton onClick={handleToggle}>{theme === 'dark' ? <DarkMode /> : <LightMode />}</IconButton>
<LanguageSwitcher />
</div>
</footer>
</main>
);

View File

@ -7,6 +7,7 @@ import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import { GetServerSideProps, NextPage } from 'next';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { useEffect } from 'react';
import toast from 'react-hot-toast';
@ -35,6 +36,8 @@ export const getServerSideProps: GetServerSideProps<Props> = async ({ query, loc
};
const Preview: NextPage<Props> = ({ shortId }) => {
const router = useRouter();
const dispatch = useAppDispatch();
const { data: resume } = useQuery<Resume>(`resume/${shortId}`, () => fetchResumeByShortId({ shortId }), {
@ -52,6 +55,14 @@ const Preview: NextPage<Props> = ({ shortId }) => {
if (resume) dispatch(setResume(resume));
}, [resume, dispatch]);
useEffect(() => {
if (resume && !isEmpty(resume) && router.locale !== resume.metadata.locale) {
const { pathname, asPath, query } = router;
router.push({ pathname, query }, asPath, { locale: resume.metadata.locale });
}
}, [resume, router]);
if (!resume || isEmpty(resume)) return null;
const layout: string[][][] = get(resume, 'metadata.layout', []);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 67 KiB

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