From e0dad6e50bb6454976aa18a459891401cef0116f Mon Sep 17 00:00:00 2001 From: Larry La Date: Fri, 25 Apr 2025 22:41:37 -0700 Subject: [PATCH 1/5] feat: markdown allowed for overview and wanted --- ...0004_alter_project_description_and_more.py | 28 + backend/projects/models.py | 6 +- frontend/bitmatch/package-lock.json | 979 +++++++++++++++++- frontend/bitmatch/package.json | 1 + .../components/project/EditProjectDialog.jsx | 36 +- frontend/bitmatch/src/index.css | 4 + .../bitmatch/src/views/AddProjectPage.jsx | 51 +- .../src/views/IndividualProjectPage.jsx | 132 +-- 8 files changed, 1116 insertions(+), 121 deletions(-) create mode 100644 backend/projects/migrations/0004_alter_project_description_and_more.py diff --git a/backend/projects/migrations/0004_alter_project_description_and_more.py b/backend/projects/migrations/0004_alter_project_description_and_more.py new file mode 100644 index 0000000..23a496d --- /dev/null +++ b/backend/projects/migrations/0004_alter_project_description_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.1.7 on 2025-04-26 05:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0003_remove_project_match_percentage'), + ] + + operations = [ + migrations.AlterField( + model_name='project', + name='description', + field=models.TextField(max_length=255), + ), + migrations.AlterField( + model_name='project', + name='full_description', + field=models.TextField(blank=True, max_length=2500, null=True), + ), + migrations.AlterField( + model_name='project', + name='wanted_description', + field=models.TextField(blank=True, max_length=2500, null=True), + ), + ] diff --git a/backend/projects/models.py b/backend/projects/models.py index 25bf6c8..331a5d0 100644 --- a/backend/projects/models.py +++ b/backend/projects/models.py @@ -10,7 +10,7 @@ class Project(models.Model): # REQUIRED title = models.CharField(max_length=255, blank=False, null=False) institution = models.CharField(max_length=255, blank=False, null=False) - description = models.TextField(blank=False, null=False) + description = models.TextField(max_length=255,blank=False, null=False) positions = models.JSONField(default=list) image_url = models.ImageField(upload_to="projects/", blank=False, null=False) @@ -22,11 +22,11 @@ class Project(models.Model): images = models.JSONField(default=list, blank=True) interest_tags = ArrayField(models.CharField(max_length=225), blank=True, null=True) skill_tags = ArrayField(models.CharField(max_length=225), blank=True, null=True) - full_description = models.CharField(max_length=1000, blank=True, null=True) + full_description = models.TextField(max_length=2500, blank=True, null=True) email = models.EmailField(unique=True, blank=True, null=True) other_contact = models.CharField(max_length=225, blank=True, null=True) updates = ArrayField(models.CharField(max_length=540), blank=True, null=True) - wanted_description = models.CharField(max_length=540, blank=True, null=True) + wanted_description = models.TextField(max_length=2500, blank=True, null=True) members = models.ManyToManyField( 'userauth.User', diff --git a/frontend/bitmatch/package-lock.json b/frontend/bitmatch/package-lock.json index 544d65d..94d3783 100644 --- a/frontend/bitmatch/package-lock.json +++ b/frontend/bitmatch/package-lock.json @@ -19,6 +19,7 @@ "@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-toast": "^1.2.7", "@radix-ui/react-toggle": "^1.1.2", + "@uiw/react-md-editor": "^4.0.5", "axios": "^1.8.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -282,6 +283,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.26.8", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz", @@ -2482,6 +2494,11 @@ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==" + }, "node_modules/@types/react": { "version": "19.0.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.8.tgz", @@ -2504,6 +2521,97 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, + "node_modules/@uiw/copy-to-clipboard": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.17.tgz", + "integrity": "sha512-O2GUHV90Iw2VrSLVLK0OmNIMdZ5fgEg4NhvtwINsX+eZ/Wf6DWD0TdsK9xwV7dNRnK/UI2mQtl0a2/kRgm1m1A==", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/@uiw/react-markdown-preview": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@uiw/react-markdown-preview/-/react-markdown-preview-5.1.3.tgz", + "integrity": "sha512-jV02wO4XHWFk54kz7sLqOkdPgJLttSfKLyen47XgjcyGgQXU2I4WJBygmdpV2AT9m/MiQ8qrN1Y+E5Syv9ZDpw==", + "dependencies": { + "@babel/runtime": "^7.17.2", + "@uiw/copy-to-clipboard": "~1.0.12", + "react-markdown": "~9.0.1", + "rehype-attr": "~3.0.1", + "rehype-autolink-headings": "~7.1.0", + "rehype-ignore": "^2.0.0", + "rehype-prism-plus": "2.0.0", + "rehype-raw": "^7.0.0", + "rehype-rewrite": "~4.0.0", + "rehype-slug": "~6.0.0", + "remark-gfm": "~4.0.0", + "remark-github-blockquote-alert": "^1.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/react-markdown": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.3.tgz", + "integrity": "sha512-Yk7Z94dbgYTOrdk41Z74GoKA7rThnsbbqBTRYuxoe08qvfQ9tJVhmAKw6BJS/ZORG7kTy/s1QvYzSuaoBA1qfw==", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.0.tgz", + "integrity": "sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ==", + "dependencies": { + "hast-util-to-string": "^3.0.0", + "parse-numeric-range": "^1.3.0", + "refractor": "^4.8.0", + "rehype-parse": "^9.0.0", + "unist-util-filter": "^5.0.0", + "unist-util-visit": "^5.0.0" + } + }, + "node_modules/@uiw/react-md-editor": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@uiw/react-md-editor/-/react-md-editor-4.0.5.tgz", + "integrity": "sha512-x+S7ZMz1B+KwVODOZk663H2gdOZhcFsrPUF8V69K4L2BbTZ3A4sBCw/uTrBE9dHH0gajAzRAYbAYCHsUQaTcyA==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "@uiw/react-markdown-preview": "^5.0.6", + "rehype": "~13.0.0", + "rehype-prism-plus": "~2.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -2879,6 +2987,15 @@ ], "license": "MIT" }, + "node_modules/bcp-47-match": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", + "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/bignumber.js": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", @@ -2899,6 +3016,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3233,6 +3355,21 @@ "node": ">= 8" } }, + "node_modules/css-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.1.2.tgz", + "integrity": "sha512-WfUcL99xWDs7b3eZPoRszWVfbNo8ErCF15PTvVROjkShGlAfjIkG6hlfj/sl6/rfo5Q9x9ryJ3VqVnAZDA+gcw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3408,6 +3545,18 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, + "node_modules/direction": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", + "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", + "bin": { + "direction": "cli.js" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -3463,6 +3612,17 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, + "node_modules/entities": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz", + "integrity": "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-abstract": { "version": "1.23.9", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", @@ -4260,6 +4420,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -4480,6 +4645,162 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-has-property": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", + "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-select": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-6.0.4.tgz", + "integrity": "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "bcp-47-match": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "css-selector-parser": "^3.0.0", + "devlop": "^1.0.0", + "direction": "^2.0.0", + "hast-util-has-property": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "nth-check": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", @@ -4506,6 +4827,45 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", @@ -4518,6 +4878,22 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/html-url-attributes": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", @@ -4527,6 +4903,15 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -5281,6 +5666,15 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -5289,21 +5683,47 @@ "node": ">= 0.4" } }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", - "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", "dependencies": { "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" }, @@ -5312,6 +5732,101 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-mdx-expression": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", @@ -5509,6 +6024,120 @@ "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromark-factory-destination": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", @@ -6010,6 +6639,17 @@ "node": ">=0.10.0" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -6221,6 +6861,22 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6751,6 +7407,76 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/refractor": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-4.9.0.tgz", + "integrity": "sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prismjs": "^1.0.0", + "hastscript": "^7.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/refractor/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + }, + "node_modules/refractor/node_modules/hast-util-parse-selector": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", + "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "dependencies": { + "@types/hast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/refractor/node_modules/hastscript": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", + "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/refractor/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -6771,6 +7497,187 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/rehype": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", + "dependencies": { + "@types/hast": "^3.0.0", + "rehype-parse": "^9.0.0", + "rehype-stringify": "^10.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-attr": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/rehype-attr/-/rehype-attr-3.0.3.tgz", + "integrity": "sha512-Up50Xfra8tyxnkJdCzLBIBtxOcB2M1xdeKe1324U06RAvSjYm7ULSeoM+b/nYPQPVd7jsXJ9+39IG1WAJPXONw==", + "dependencies": { + "unified": "~11.0.0", + "unist-util-visit": "~5.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/rehype-autolink-headings": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz", + "integrity": "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-ignore": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/rehype-ignore/-/rehype-ignore-2.0.2.tgz", + "integrity": "sha512-BpAT/3lU9DMJ2siYVD/dSR0A/zQgD6Fb+fxkJd4j+wDVy6TYbYpK+FZqu8eM9EuNKGvi4BJR7XTZ/+zF02Dq8w==", + "dependencies": { + "hast-util-select": "^6.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/rehype-parse": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-prism-plus": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.1.tgz", + "integrity": "sha512-Wglct0OW12tksTUseAPyWPo3srjBOY7xKlql/DPKi7HbsdZTyaLCAoO58QBKSczFQxElTsQlOY3JDOFzB/K++Q==", + "dependencies": { + "hast-util-to-string": "^3.0.0", + "parse-numeric-range": "^1.3.0", + "refractor": "^4.8.0", + "rehype-parse": "^9.0.0", + "unist-util-filter": "^5.0.0", + "unist-util-visit": "^5.0.0" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-rewrite": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rehype-rewrite/-/rehype-rewrite-4.0.2.tgz", + "integrity": "sha512-rjLJ3z6fIV11phwCqHp/KRo8xuUCO8o9bFJCNw5o6O2wlLk6g8r323aRswdGBQwfXPFYeSuZdAjp4tzo6RGqEg==", + "dependencies": { + "hast-util-select": "^6.0.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "dependencies": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-github-blockquote-alert": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/remark-github-blockquote-alert/-/remark-github-blockquote-alert-1.3.0.tgz", + "integrity": "sha512-cwkBA4x+VH4J2VAMzhbmSeAmK5tBd5iwesgSUUQuRtuQ48XQm6sXXNLY9PR7ohZmZiqMeoDMUGCTur5zwR4lTQ==", + "dependencies": { + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, "node_modules/remark-parse": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", @@ -6802,6 +7709,20 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -7701,6 +8622,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-filter": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/unist-util-filter/-/unist-util-filter-5.0.1.tgz", + "integrity": "sha512-pHx7D4Zt6+TsfwylH9+lYhBhzyhEnCXs/lbq/Hstxno5z4gVdyc2WEW0asfjGKPyG4pEKrnBv5hdkO6+aRnQJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + } + }, "node_modules/unist-util-is": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", @@ -7886,6 +8817,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vfile-message": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", @@ -7970,6 +8914,15 @@ } } }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/frontend/bitmatch/package.json b/frontend/bitmatch/package.json index adce60c..68d6e6f 100644 --- a/frontend/bitmatch/package.json +++ b/frontend/bitmatch/package.json @@ -21,6 +21,7 @@ "@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-toast": "^1.2.7", "@radix-ui/react-toggle": "^1.1.2", + "@uiw/react-md-editor": "^4.0.5", "axios": "^1.8.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/frontend/bitmatch/src/components/project/EditProjectDialog.jsx b/frontend/bitmatch/src/components/project/EditProjectDialog.jsx index b495c0c..56fe7ed 100644 --- a/frontend/bitmatch/src/components/project/EditProjectDialog.jsx +++ b/frontend/bitmatch/src/components/project/EditProjectDialog.jsx @@ -16,6 +16,7 @@ import { Label } from "@/components/ui/Label"; import { Textarea } from "@/components/ui/Textarea"; import { Card } from "@/components/ui/Card"; import { useNavigate } from "react-router-dom"; +import MDEditor from "@uiw/react-md-editor"; const SERVER_HOST = import.meta.env.VITE_SERVER_HOST; @@ -167,13 +168,17 @@ export function EditProjectDialog({ open, onOpenChange, projectData, onSave }) { - +
+ setFullDescription(value || "")} + preview="edit" + height={200} + /> +
- Max Characters: 1000 + Max Characters: 2500 Character Count: {fullDescription.length}
@@ -417,9 +420,33 @@ export default function CreateProjectForm() { )} + +
+ +
+

+ Tell us more about the positions you need to fill. (overview, + responsiblities, skills required, other requirements, etc.) +

+ setWantedDescription(value || "")} + preview="edit" + height={200} + /> +
+
+ Max Characters: 2500 + Character Count: {wantedDescription.length} +
+
+
{ try { @@ -370,6 +371,7 @@ const ProjectDetailPage = () => { formData.append("description", data.description); formData.append("full_description", data.full_description); formData.append("positions", JSON.stringify(data.positions)); + formData.append("wanted_description", data.wanted_description); if (data.new_image) { formData.append("image_url", data.new_image); @@ -697,19 +699,20 @@ const ProjectDetailPage = () => {
-

Overview

+

Overview

Background & More Details About the Project

-

{project.full_description}

- +

+ {project.full_description} +

{project.interest_tags?.length > 0 && ( <>

- Project Categories + Project Categories/Tags

{project.interest_tags.map((interest, index) => ( @@ -724,23 +727,6 @@ const ProjectDetailPage = () => {
)} - - {project.skill_tags?.length > 0 && ( - <> -

Desired Skills

-
- {project.skill_tags.map((skill, index) => ( - - {skill} - - ))} -
- - )}
@@ -784,81 +770,55 @@ const ProjectDetailPage = () => {
{/* Wanted Header */} -

- Wanted{" "} - (W.I.P) -

+

Wanted

+ {/* Positions Section */}
-
-

- Positions Needed for This Project -

- -
- -
- - +
+ {project.wanted_description}
+ + {project.positions?.length > 0 && ( + <> +

Open Positions

+
+ {project.positions.map((position, index) => ( + + {position.title} + + ))} +
+ + )} + + {project.skill_tags?.length > 0 && ( + <> +

Desired Skills

+
+ {project.skill_tags.map((skill, index) => ( + + {skill} + + ))} +
+ + )}
-

+

Project Owner Contact Information{" "} (W.I.P)

From 355c882c1604475ed2aa7c51d999b2a0e41d101c Mon Sep 17 00:00:00 2001 From: Larry La Date: Sat, 26 Apr 2025 00:24:58 -0700 Subject: [PATCH 2/5] feat: all tabs new --- .../migrations/0005_alter_project_location.py | 18 + backend/projects/models.py | 2 +- backend/userauth/urls.py | 3 +- backend/userauth/views.py | 7 + .../src/components/project/MemberCard.jsx | 73 +--- .../bitmatch/src/views/AddProjectPage.jsx | 105 ++++- .../src/views/IndividualProjectPage.jsx | 401 ++++++++++-------- 7 files changed, 360 insertions(+), 249 deletions(-) create mode 100644 backend/projects/migrations/0005_alter_project_location.py diff --git a/backend/projects/migrations/0005_alter_project_location.py b/backend/projects/migrations/0005_alter_project_location.py new file mode 100644 index 0000000..2675219 --- /dev/null +++ b/backend/projects/migrations/0005_alter_project_location.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.7 on 2025-04-26 05:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0004_alter_project_description_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='project', + name='location', + field=models.CharField(max_length=255), + ), + ] diff --git a/backend/projects/models.py b/backend/projects/models.py index 331a5d0..0ae1a0f 100644 --- a/backend/projects/models.py +++ b/backend/projects/models.py @@ -18,7 +18,7 @@ class Project(models.Model): group = models.CharField(max_length=255, blank=True, null=True) followers_count = models.IntegerField(default=0) likes_count = models.IntegerField(default=0) - location = models.JSONField(default=list, blank=True) + location = models.CharField(max_length=255, blank=False, null=False) images = models.JSONField(default=list, blank=True) interest_tags = ArrayField(models.CharField(max_length=225), blank=True, null=True) skill_tags = ArrayField(models.CharField(max_length=225), blank=True, null=True) diff --git a/backend/userauth/urls.py b/backend/userauth/urls.py index d474650..d1253fd 100644 --- a/backend/userauth/urls.py +++ b/backend/userauth/urls.py @@ -1,8 +1,9 @@ from django.urls import path -from .views import UsersCRUDView, check_if_onboarded +from .views import UsersCRUDView, check_if_onboarded, fetch_by_uuid urlpatterns = [ path('onboard/', UsersCRUDView.as_view(), name='onboard-user'), # Create user path('onboard/check/', check_if_onboarded, name="onboard-check"), # Check if user onboarded path('/', UsersCRUDView.as_view(), name='user'), # Read, Update, Delete user by ID + path('fetch//', fetch_by_uuid, name='uuid-fetch'), ] diff --git a/backend/userauth/views.py b/backend/userauth/views.py index ec47b4b..14aff4b 100644 --- a/backend/userauth/views.py +++ b/backend/userauth/views.py @@ -14,6 +14,13 @@ def check_if_onboarded(request, clerk_id): return Response({"message": "User already onboarded"}) else: return Response({"message": "User not onboarded yet!"}) + +@api_view(['GET']) +@permission_classes([AllowAny]) +def fetch_by_uuid(request, uuid): + user = get_object_or_404(User, pk=uuid) + serializer = UserSerializer(user) + return Response(serializer.data) # DRF CRUD views for Users model class UsersCRUDView(APIView): diff --git a/frontend/bitmatch/src/components/project/MemberCard.jsx b/frontend/bitmatch/src/components/project/MemberCard.jsx index cf4c130..b4bcbb1 100644 --- a/frontend/bitmatch/src/components/project/MemberCard.jsx +++ b/frontend/bitmatch/src/components/project/MemberCard.jsx @@ -1,63 +1,30 @@ "use client"; -import { Button } from "@/components/ui/button"; +import { Link } from "react-router-dom"; -export function MemberCard({ - name, - position, - joinDate, - profileImage, - onAssignPosition, - onPermissions, - onRemove, -}) { +export function MemberCard({ name, position, joinDate, profileImage, authId }) { return (
-
- {profileImage ? ( - {`${name}'s - ) : ( - - img -
- profile -
- )} +
+ {`${name}'s
-

{name}

-

{position}

-

{joinDate}

-
-
- - - + {authId ? ( + + {name} + + ) : ( +

{name}

+ )} +

{position || "Contributor"}

); -} \ No newline at end of file +} diff --git a/frontend/bitmatch/src/views/AddProjectPage.jsx b/frontend/bitmatch/src/views/AddProjectPage.jsx index ce633a1..0348db5 100644 --- a/frontend/bitmatch/src/views/AddProjectPage.jsx +++ b/frontend/bitmatch/src/views/AddProjectPage.jsx @@ -22,6 +22,9 @@ export default function CreateProjectForm() { const [projectName, setProjectName] = useState(""); const [university, setUniversity] = useState(""); const [group, setGroup] = useState(""); + const [projectMail, setProjectMail] = useState(""); + const [projectSocial, setProjectSocial] = useState(""); + const [projectLocation, setProjectLocation] = useState(""); const [shortDescription, setShortDescription] = useState(""); const [fullDescription, setFullDescription] = useState(""); const [wantedDescription, setWantedDescription] = useState(""); @@ -29,17 +32,7 @@ export default function CreateProjectForm() { const [newRole, setNewRole] = useState(""); const [coverImagePreview, setCoverImagePreview] = useState(null); const [coverImageFile, setCoverImageFile] = useState(null); - const [sliderImages, setSliderImages] = useState([ - "slideshow_img1.jpg", - "slideshow_img2.jpg", - "slideshow_img3.jpg", - "slideshow_img4.jpg", - "slideshow_img5.jpg", - ]); - const [selectedCategories, setSelectedCategories] = useState([ - "Technology", - "Health & Fitness", - ]); + const [sliderImages, setSliderImages] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(""); const [roleError, setRoleError] = useState(""); @@ -91,10 +84,10 @@ export default function CreateProjectForm() { } }; - const handleFullDescriptionChange = (e) => { - if (e.target.value.length <= 2500) { - setFullDescription(e.target.value); - } + const handleImageUrlChange = (index, event) => { + const newUrls = [...sliderImages]; + newUrls[index] = event.target.value; + setSliderImages(newUrls); }; const handleAddRole = () => { @@ -142,11 +135,15 @@ export default function CreateProjectForm() { formData.append("title", projectName); formData.append("institution", university); formData.append("group", group); + formData.append("email", projectMail); + formData.append("other_contact", projectSocial); + formData.append("location", projectLocation); formData.append("description", shortDescription); formData.append("wanted_description", wantedDescription); formData.append("full_description", fullDescription); formData.append("positions", JSON.stringify(roles)); formData.append("image_url", coverImageFile); + formData.append("images", JSON.stringify(sliderImages)); formData.append("owner", userUuid); skills.forEach((skill) => { formData.append("skill_tags", skill); @@ -277,6 +274,33 @@ export default function CreateProjectForm() { />
+ +
+

Slider Images (Optional)

+

+ Enter up to 4 image URLs for populating the image carousel on your + project page. (Ex: screenshots of app, mockups, etc) +

+ +
+ {[...Array(4)].map((_, index) => ( +
+ handleImageUrlChange(index, e)} // Update the state on change + className="w-full h-10 border border-gray-300 p-2 rounded-md" + /> +
+ ))} +
+ +

+ Example: https://example.com/image1.jpg +

+
@@ -310,6 +334,57 @@ export default function CreateProjectForm() { />
+
+ + setProjectLocation(e.target.value)} + required + /> +
+ +
+ + setProjectMail(e.target.value)} + required + /> +

+ At what email can the project owner/management be reached at? +

+
+ +
+ + setProjectSocial(e.target.value)} + /> +

+ What social medias can the project owner/managment be reached at? + (Discord, X, Facebook, Etc.) +

+
+
diff --git a/frontend/bitmatch/src/views/IndividualProjectPage.jsx b/frontend/bitmatch/src/views/IndividualProjectPage.jsx index 84b195e..3d3ffcb 100644 --- a/frontend/bitmatch/src/views/IndividualProjectPage.jsx +++ b/frontend/bitmatch/src/views/IndividualProjectPage.jsx @@ -71,85 +71,49 @@ const ProjectDetailPage = () => { const [memberData, setMemberData] = useState([]); useEffect(() => { - const fetchUserUuid = async () => { - try { - const response = await fetch(`${SERVER_HOST}/userauth/${user.id}`); - if (!response.ok) { - throw new Error("Failed to fetch user data"); - } - const data = await response.json(); - setuserData(data); - setUserUuid(data.id); - } catch (error) { - console.error("Error fetching user UUID:", error); - } - }; + const fetchData = async () => { + setLoading(true); - fetchUserUuid(); - }, [user.id]); - - useEffect(() => { - // Fetch project details when the component mounts or the `id` changes - const loadProjectInfo = async () => { try { - setLoading(true); - const data = await fetchProjectInfo(id); - if (data) { - setProject(data); - } else { - setError("Project not found."); - } - // eslint-disable-next-line no-unused-vars - } catch (err) { - setError("Failed to load project details."); + const [userResponse, projectData] = await Promise.all([ + fetch(`${SERVER_HOST}/userauth/${user.id}`), + fetchProjectInfo(id), + ]); + + if (!userResponse.ok) throw new Error("Failed to fetch user data"); + const userData = await userResponse.json(); + setuserData(userData); + setUserUuid(userData.id); + + if (!projectData) throw new Error("Project not found."); + setProject(projectData); + + setIsMember(projectData.members.includes(userData.id)); + + const memberPromises = projectData.members + .slice(0, 10) + .map((uuid) => + fetch(`${SERVER_HOST}/userauth/fetch/${uuid}/`).then((res) => + res.ok ? res.json() : null + ) + ); + const memberResults = await Promise.all(memberPromises); + setMemberData(memberResults.filter((member) => member !== null)); + + const ownerData = await fetchUserByUUID(projectData.owner); + setOwnerData(ownerData); + + setIsReady(true); + } catch (error) { + setError("Error loading data"); + console.error(error); } finally { setLoading(false); } }; - loadProjectInfo(); - }, [id, userUuid]); - - useEffect(() => { - if (userData && project) { - setIsMember(project.members.includes(userData.id)); - setIsReady(true); - } - }, [userData, project]); - - useEffect(() => { - const fetchAllMembers = async () => { - if (!project || !project.members || project.members.length === 0) return; - - try { - const promises = project.members.map((uuid) => - fetch(`${SERVER_HOST}/userauth/fetch/${uuid}/`).then((res) => - res.ok ? res.json() : null - ) - ); - - const results = await Promise.all(promises); - - const validMembers = results.filter((member) => member !== null); - - setMemberData(validMembers); - } catch (error) { - console.error("Failed to fetch member data:", error); - } - }; - - fetchAllMembers(); - }, [project]); - - useEffect(() => { - const fetchOwnerData = async () => { - const data = await fetchUserByUUID(project.owner); - if (data) { - setOwnerData(data); - } - }; - fetchOwnerData(); - }, [project]); + fetchData(); + }, [user.id, id]); const fetchUserByUUID = async (userId) => { try { @@ -278,6 +242,7 @@ const ProjectDetailPage = () => { --- DO NOT ask for additional information or clarification. + DO NOT USE HTML CODE TO FORMAT Format it cleanly with section headers, a prominent rating at the top, and spacing between each section. @@ -300,6 +265,9 @@ const ProjectDetailPage = () => { ---PROJECT POSITIONS NEEDED--- ${project.positions.map((position) => position.title).join(", ")} + + ---PROJECT WANTED DESCRIPTION--- + ${project.wanted_description} `, }); setAI_Response(response.text); @@ -313,7 +281,7 @@ const ProjectDetailPage = () => { const response = await AI.models.generateContent({ model: "gemini-2.0-flash", contents: ` - You are a professional evaluator. + You are a professional evaluator who doesn't like to sugarcoat things. Based ONLY on the information provided, give the following feedback on how good of a fit I am for the project. NOTE: If the input data looks like a test record just respond "Can't rate, this is a test record!" @@ -341,6 +309,7 @@ const ProjectDetailPage = () => { --- DO NOT ask for additional information or clarification. + DO NOT USE HTML CODE TO FORMAT Format it cleanly with section headers, a prominent fit rating at the top, and spacing between each section. --- @@ -366,6 +335,9 @@ const ProjectDetailPage = () => { ---PROJECT POSITIONS NEEDED--- ${project.positions.map((position) => position.title).join(", ")} +---PROJECT WANTED DESCRIPTION--- + ${project.wanted_description} + ---USER INTERESTS--- ${userData.interests} @@ -415,7 +387,6 @@ const ProjectDetailPage = () => { const handleSave = async (data) => { const formData = new FormData(); - console.log(data); formData.append("title", data.title); formData.append("group", data.group); formData.append("location", data.location); @@ -428,6 +399,22 @@ const ProjectDetailPage = () => { formData.append("images", JSON.stringify(data.images)); formData.append("wanted_description", data.wanted_description); + if (Array.isArray(data.interest_tags)) { + data.interest_tags.forEach((interest) => { + formData.append("interest_tags", interest); + }); + } else { + formData.append("interest_tags", data.interest_tags); + } + + if (Array.isArray(data.skill_tags)) { + data.skill_tags.forEach((skill) => { + formData.append("skill_tags", skill); + }); + } else { + formData.append("skill_tags", data.skill_tags); + } + if (data.new_image) { formData.append("image_url", data.new_image); } @@ -756,12 +743,12 @@ const ProjectDetailPage = () => {

Overview

-

-

+
+
Background & More Details About the Project -

+
{project.full_description} -

+
{project.interest_tags?.length > 0 && ( <> @@ -898,7 +885,7 @@ const ProjectDetailPage = () => { πŸ€– AI Rate My Project πŸ€–

- Let AI rate your project and give feedback. + Let AI rate your project idea and give feedback.