diff --git a/.eslintrc.js b/.eslintrc.js index f4d2412f..dd38df4b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -78,8 +78,8 @@ module.exports = { ], rules: { "import/no-named-as-default": 0, - "@typescript-eslint/no-explicit-any": "warn" - } + "@typescript-eslint/no-explicit-any": "warn", + }, }, // Markdown @@ -115,7 +115,7 @@ module.exports = { "jest/no-standalone-expect": "off", "testing-library/no-node-access": "warn", "testing-library/no-container": "warn", - } + }, }, // Cypress diff --git a/app/core/components/ApplicantComments/index.tsx b/app/core/components/ApplicantComments/index.tsx index 45eb303e..d3f8dbba 100644 --- a/app/core/components/ApplicantComments/index.tsx +++ b/app/core/components/ApplicantComments/index.tsx @@ -11,7 +11,6 @@ import { Paper, IconButton, } from "@mui/material"; -import type { internsComments as CommentType, Profiles } from "@prisma/client"; import { Form, useNavigation } from "@remix-run/react"; import { withZod } from "@remix-validated-form/with-zod"; import Markdown from "marked-react"; @@ -22,11 +21,9 @@ import { zfd } from "zod-form-data"; import type { getCommentsApplicant } from "~/models/applicantComment.server"; import { validateNavigationRedirect } from "~/utils"; +type Optional = Pick, K> & Omit; type CommentsArrayType = Awaited>; -type CommentItemType = CommentType & { - author?: Profiles; - children?: CommentType[]; -}; +type CommentItemType = Optional; export const validator = withZod( zfd.formData({ @@ -104,10 +101,10 @@ function CommentItem({ - + - {`${comment.author?.preferredName} ${comment.author?.lastName}`} + {`${comment.authorPreferredName} ${comment.authorLastName}`} {comment.updatedAt.toLocaleString()} diff --git a/app/core/components/Comments.tsx b/app/core/components/Comments.tsx index bbb049a3..6f6ed2b1 100644 --- a/app/core/components/Comments.tsx +++ b/app/core/components/Comments.tsx @@ -11,7 +11,6 @@ import { Paper, IconButton, } from "@mui/material"; -import type { Comments as CommentType, Profiles } from "@prisma/client"; import { Form, useNavigation } from "@remix-run/react"; import { withZod } from "@remix-validated-form/with-zod"; import Markdown from "marked-react"; @@ -22,11 +21,9 @@ import { zfd } from "zod-form-data"; import type { getComments } from "~/models/comment.server"; import { validateNavigationRedirect } from "~/utils"; +type Optional = Pick, K> & Omit; type CommentsArrayType = Awaited>; -type CommentItemType = CommentType & { - author?: Profiles; - children?: CommentType[]; -}; +type CommentItemType = Optional; export const validator = withZod( zfd.formData({ @@ -104,10 +101,10 @@ function CommentItem({ - + - {`${comment.author?.preferredName} ${comment.author?.lastName}`} + {`${comment.authorPreferredName} ${comment.authorLastName}`} {comment.updatedAt.toLocaleString()} diff --git a/app/core/components/RegularSelect/index.tsx b/app/core/components/RegularSelect/index.tsx index 6460591a..5a4eb6a5 100644 --- a/app/core/components/RegularSelect/index.tsx +++ b/app/core/components/RegularSelect/index.tsx @@ -5,7 +5,6 @@ import { InputLabel, FormHelperText, } from "@mui/material"; -import { useState } from "react"; import { useControlField, useField } from "remix-validated-form"; interface SelectValue { @@ -36,7 +35,6 @@ export const RegularSelect = ({ const [value, setValue] = useControlField(name); //This state variable is to have a controlled input and avoid errors in the console - const [selectValue, setSelectValue] = useState(""); return ( @@ -44,23 +42,22 @@ export const RegularSelect = ({ {label} - DRAFT - HOLD - ACCEPTED - REJECTED - - + + + + Status: {applicant.status} + + + {applicant.projectName ? ( - Project: {applicant.project?.name} + Project: {applicant.projectName} + ) : null} + {applicant.mentorPreferredName ? ( - Mentor: {applicant.mentor?.preferredName}{" "} - {applicant.mentor?.lastName}{" "} + Mentor: {applicant.mentorPreferredName}{" "} + {applicant.mentorLastName}{" "} - - ) : null} + ) : null} +
@@ -301,7 +270,7 @@ export default function Applicant() { ) : null}
- {applicant.university?.name} / {applicant.major} /{" "} + {applicant.universityName} / {applicant.major} /{" "} {applicant.semester} / {applicant.englishLevel}
@@ -311,9 +280,8 @@ export default function Applicant() { {applicant.phone ? ( ) : null} - {applicant.universityPointOfContact - ? " / University contact: " + - applicant.universityPointOfContact.fullName + {applicant.pocName + ? " / University contact: " + applicant.pocName : null}
@@ -395,15 +363,37 @@ export default function Applicant() { -

Select project and mentor

+

Edit internship status

- + + + Status + + - - option.id === value.id} - id="mentor" - getOptionLabel={(option) => option.name} - onInputChange={(_, value) => searchProfilesDebounced(value)} - renderTags={() => null} - onChange={( - event, - value: { id: string; name: string } | null, - reason: AutocompleteChangeReason - ) => - reason === "clear" - ? setMentorSelected({ id: "", name: "" }) - : setMentorSelected(value) - } - filterSelectedOptions - renderInput={(params) => ( - - )} + + - +
diff --git a/app/routes/applicants.$applicantId.status.tsx b/app/routes/applicants.$applicantId.status.tsx index 435dd814..9c100838 100644 --- a/app/routes/applicants.$applicantId.status.tsx +++ b/app/routes/applicants.$applicantId.status.tsx @@ -9,17 +9,13 @@ export const action: ActionFunction = async ({ request }) => { const result = await validator.validate(await request.formData()); const applicantId = parseInt(result.data?.applicantId as string); const status = result.data?.status; - let projectId = null; - let mentorId = null; - let response = null; - if (status !== "DRAFT") { - projectId = result.data?.project?.id - ? result.data?.project.id - : result.data?.projectId; - mentorId = result.data?.mentorId; - } // else reset the values - console.log("action", mentorId, projectId, status, applicantId); - response = await editApplicant({ mentorId, projectId, status }, applicantId); - console.log("response", response.status); - return redirect(`/applicants/${response.id}&status=${response.status}`); + const response = await editApplicant( + { + mentorId: result.data?.mentor?.id, + projectId: result.data?.project?.id, + status, + }, + applicantId + ); + return redirect(`/applicants/${response.id}?status=${response.status}`); }; diff --git a/app/routes/applicants._index.tsx b/app/routes/applicants._index.tsx index cb1e4d03..44b8abed 100644 --- a/app/routes/applicants._index.tsx +++ b/app/routes/applicants._index.tsx @@ -27,11 +27,13 @@ export const loader = async () => { dayOfBirth: a.dayOfBirth, graduationDate: a.graduationDate, hoursPerWeek: a.hoursPerWeek, - university: a.university?.name, + university: a.universityName, semester: a.semester, participatedAtWizeline: a.participatedAtWizeline, status: a.status, appliedProjects: a.appliedProjects, + preferredTools: a.preferredTools, + interestedRoles: a.interestedRoles, })) ); }; @@ -115,6 +117,16 @@ export default function Projects() { REJECTED: "REJECTED", }, }, + { + field: "preferredTools", + title: "Preferred Tools", + hidden: true, + }, + { + field: "interestedRoles", + title: "Interested Roles", + hidden: true, + }, { field: "appliedProjects", title: "Applied Projects", diff --git a/app/routes/internshipProjects._index.tsx b/app/routes/internshipProjects._index.tsx index 569c4158..461e6438 100644 --- a/app/routes/internshipProjects._index.tsx +++ b/app/routes/internshipProjects._index.tsx @@ -26,7 +26,7 @@ import TableRow from "@mui/material/TableRow"; import { useLoaderData, useSearchParams } from "@remix-run/react"; import type { LoaderFunction } from "@remix-run/server-runtime"; import { mentorDiscipline } from "~/constants"; -import { getApplicantByEmail } from "~/models/applicant.server"; +import { existApplicant, getApplicantByEmail } from "~/models/applicant.server"; import { searchDisciplineByName } from "~/models/discipline.server"; import { getProjectsByRole } from "~/models/project.server"; import { requireProfile } from "~/session.server"; @@ -42,14 +42,14 @@ export const loader: LoaderFunction = async ({ request }) => { const id = await searchDisciplineByName(mentorDiscipline); const { projects, count } = await getProjectsByRole(id?.id as string); const profile = await requireProfile(request); - const existApplicant = await getApplicantByEmail(profile.email); + const doesExistApplicant = await existApplicant(profile.email); const applicant = await getApplicantByEmail(profile.email); return { projects, count, id, - existApplicant, + existApplicant: doesExistApplicant, applicant, }; } catch (error) { diff --git a/app/routes/notes.tsx b/app/routes/notes.tsx deleted file mode 100644 index 7027abd6..00000000 --- a/app/routes/notes.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import type { LoaderFunction } from "@remix-run/node"; -import { json } from "@remix-run/node"; -import { Form, Link, NavLink, Outlet, useLoaderData } from "@remix-run/react"; -import { getNoteListItems } from "~/models/note.server"; -import { requireUserId } from "~/session.server"; -import { useUser } from "~/utils"; - -interface LoaderData { - noteListItems: Awaited>; -} - -export const loader: LoaderFunction = async ({ request }) => { - const userId = await requireUserId(request); - const noteListItems = await getNoteListItems({ userId }); - return json({ noteListItems }); -}; - -export default function NotesPage() { - const data = useLoaderData() as LoaderData; - const user = useUser(); - - return ( -
-
-

- Notes -

-

{user.email}

-
- -
-
- -
-
- - + New Note - - -
- - {data.noteListItems.length === 0 ? ( -

No notes yet

- ) : ( -
    - {data.noteListItems.map((note) => ( -
  1. - - `block border-b p-4 text-xl ${isActive ? "bg-white" : ""}` - } - to={note.id} - > - 📝 {note.title} - -
  2. - ))} -
- )} -
- -
- -
-
-
- ); -} diff --git a/app/singleton.server.ts b/app/singleton.server.ts index 3e179aa5..585ad84e 100644 --- a/app/singleton.server.ts +++ b/app/singleton.server.ts @@ -4,7 +4,7 @@ export const singleton = ( name: string, - valueFactory: () => Value, + valueFactory: () => Value ): Value => { const g = global as unknown as { __singletons: Record }; g.__singletons ??= {}; diff --git a/package-lock.json b/package-lock.json index 73969c96..a4b7432f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,9 @@ "chart.js": "^4.4.0", "date-fns": "^2.29.2", "isbot": "^4", + "kysely": "^0.27.2", "marked-react": "^1.2.0", + "pg": "^8.11.3", "react": "^18.2.0", "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", @@ -36,6 +38,7 @@ "remix-typedjson": "^0.4.1", "remix-validated-form": "^5.1.0", "tiny-invariant": "^1.3.1", + "uuid": "^9.0.1", "zod": "^3.19.1", "zod-form-data": "^1.2.4" }, @@ -55,8 +58,10 @@ "@types/cookie": "^0.6.0", "@types/eslint": "^8.44.6", "@types/node": "^20.0.0", + "@types/pg": "^8.11.0", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", + "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^6.8.0", "@typescript-eslint/parser": "^6.8.0", "@vitejs/plugin-react": "^4.2.1", @@ -81,6 +86,7 @@ "eslint-plugin-testing-library": "^6.1.0", "happy-dom": "^6.0.4", "husky": "^8.0.3", + "kysely-codegen": "^0.11.0", "lint-staged": "^13.1.0", "msw": "^2.1.7", "npm-run-all": "^4.1.5", @@ -3743,6 +3749,74 @@ "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" }, + "node_modules/@types/pg": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.0.tgz", + "integrity": "sha512-sDAlRiBNthGjNFfvt0k6mtotoVYVQ63pA8R4EMWka7crawSR60waVYR0HAgmPRs/e2YaeJTD/43OoZ3PFw80pw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, + "node_modules/@types/pg/node_modules/pg-types": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", + "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", + "dev": true, + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.1.0", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/pg/node_modules/postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "dev": true, + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/pg/node_modules/postgres-date": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/@types/prismjs": { "version": "1.26.3", "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz", @@ -3831,6 +3905,12 @@ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -5211,6 +5291,14 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, "node_modules/builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -8683,6 +8771,102 @@ "assert-plus": "^1.0.0" } }, + "node_modules/git-diff": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/git-diff/-/git-diff-2.0.6.tgz", + "integrity": "sha512-/Iu4prUrydE3Pb3lCBMbcSNIf81tgGt0W1ZwknnyF62t3tHmtiJTRj0f+1ZIhp3+Rh0ktz1pJVoa7ZXUCskivA==", + "dev": true, + "dependencies": { + "chalk": "^2.3.2", + "diff": "^3.5.0", + "loglevel": "^1.6.1", + "shelljs": "^0.8.1", + "shelljs.exec": "^1.1.7" + }, + "engines": { + "node": ">= 4.8.0" + } + }, + "node_modules/git-diff/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-diff/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-diff/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/git-diff/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/git-diff/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/git-diff/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/git-diff/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-diff/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", @@ -9593,6 +9777,15 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -10491,6 +10684,54 @@ "node": ">=6" } }, + "node_modules/kysely": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.2.tgz", + "integrity": "sha512-DmRvEfiR/NLpgsTbSxma2ldekhsdcd65+MNiKXyd/qj7w7X5e3cLkXxcj+MypsRDjPhHQ/CD5u3Eq1sBYzX0bw==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/kysely-codegen": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/kysely-codegen/-/kysely-codegen-0.11.0.tgz", + "integrity": "sha512-8aklzXygjANshk5BoGSQ0BWukKIoPL4/k1iFWyteGUQ/VtB1GlyrELBZv1GglydjLGECSSVDpsOgEXyWQmuksg==", + "dev": true, + "dependencies": { + "chalk": "4.1.2", + "dotenv": "^16.0.3", + "git-diff": "^2.0.6", + "micromatch": "^4.0.5", + "minimist": "^1.2.8" + }, + "bin": { + "kysely-codegen": "dist/cli/bin.js" + }, + "peerDependencies": { + "@libsql/kysely-libsql": "^0.3.0", + "better-sqlite3": ">=7.6.2", + "kysely": ">=0.19.12", + "mysql2": "^2.3.3 || ^3.0.0", + "pg": "^8.8.0" + }, + "peerDependenciesMeta": { + "@libsql/kysely-libsql": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "kysely": { + "optional": false + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + } + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -11159,6 +11400,19 @@ "node": ">=8" } }, + "node_modules/loglevel": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz", + "integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -13819,6 +14073,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -13973,6 +14233,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "node_modules/pako": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", @@ -14243,6 +14508,98 @@ "is-reference": "^3.0.0" } }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -14482,6 +14839,47 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-range": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", + "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", + "dev": true + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -15098,6 +15496,18 @@ "node": ">=8.10.0" } }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -16183,6 +16593,74 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs.exec": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/shelljs.exec/-/shelljs.exec-1.1.8.tgz", + "integrity": "sha512-vFILCw+lzUtiwBAHV8/Ex8JsFjelFMdhONIsgKNLgTzeRckp2AOYRQtHJE/9LhNvdMmE27AGtzWx0+DHpwIwSw==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/shelljs/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/shelljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/shelljs/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/side-channel": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", @@ -16322,6 +16800,14 @@ "node": "*" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", @@ -18965,7 +19451,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, "engines": { "node": ">=0.4" } diff --git a/package.json b/package.json index 14bbd02a..643ace09 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "validate": "run-p \"test -- --run\" lint typecheck test:e2e:run", "migrate-profiles-lake": "ts-node --project ./ts-node.tsconfig.json ./tasks/ProfilesMigration/migrateProfilesLake.ts", "get-gitprojects-activity": "ts-node --project ./ts-node.tsconfig.json ./tasks/GitHubDataManage/getGitHubActivityByProject.ts", - "prepare": "husky install" + "prepare": "husky install", + "kysely-codegen": "kysely-codegen --out-file app/kysely.d.ts" }, "eslintIgnore": [ "/node_modules", @@ -53,7 +54,9 @@ "chart.js": "^4.4.0", "date-fns": "^2.29.2", "isbot": "^4", + "kysely": "^0.27.2", "marked-react": "^1.2.0", + "pg": "^8.11.3", "react": "^18.2.0", "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", @@ -63,6 +66,7 @@ "remix-typedjson": "^0.4.1", "remix-validated-form": "^5.1.0", "tiny-invariant": "^1.3.1", + "uuid": "^9.0.1", "zod": "^3.19.1", "zod-form-data": "^1.2.4" }, @@ -82,8 +86,10 @@ "@types/cookie": "^0.6.0", "@types/eslint": "^8.44.6", "@types/node": "^20.0.0", + "@types/pg": "^8.11.0", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", + "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^6.8.0", "@typescript-eslint/parser": "^6.8.0", "@vitejs/plugin-react": "^4.2.1", @@ -108,6 +114,7 @@ "eslint-plugin-testing-library": "^6.1.0", "happy-dom": "^6.0.4", "husky": "^8.0.3", + "kysely-codegen": "^0.11.0", "lint-staged": "^13.1.0", "msw": "^2.1.7", "npm-run-all": "^4.1.5", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index f1d13aa7..7622ec8f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -390,116 +390,115 @@ model RelatedProjects { } model internsComments { - id String @id @default(uuid()) + id String @id @default(uuid()) body String authorId String applicantId Int - createdAt DateTime @default(now()) - updatedAt DateTime @default(now()) + createdAt DateTime @default(now()) + updatedAt DateTime @default(now()) parentId String? - author Profiles @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade) + author Profiles @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade) parent internsComments? @relation("ParentComment", fields: [parentId], references: [id], onDelete: Cascade, onUpdate: Cascade) - applicant Applicant @relation(fields: [applicantId], references: [id], onDelete: Cascade, onUpdate: Cascade) + applicant Applicant @relation(fields: [applicantId], references: [id], onDelete: Cascade, onUpdate: Cascade) children internsComments[] @relation("ParentComment") } model Applicant { - id Int @id @default(autoincrement()) - createdAt DateTime @default(now()) - email String @unique - personalEmail String - fullName String - nationality String - country String - dayOfBirth DateTime - homeAddress String - phone String - universityEmail String? - emergencyContactName String? - emergencyContactPhone String? - emergencyRelationship String? - gender String - englishLevel String - universityId String? - university Universities? @relation(fields: [universityId], references: [id], onDelete: Cascade, onUpdate: Cascade) - universityPointOfContactId String? - universityPointOfContact UniversityPointsOfContact? @relation(fields: [universityPointOfContactId], references: [id], onDelete: Cascade, onUpdate: Cascade) - major String - semester String - graduationDate DateTime - interest String - experience String - cvLink String - interestedRoles String? - preferredTools String? - startDate DateTime - endDate DateTime - hoursPerWeek Int - howDidYouHearAboutUs String - participatedAtWizeline Boolean - wizelinePrograms String? - status String @default("DRAFT") - mentorId String? - comments String? - appliedProjects String? - appliedProjectsId String? - generalComments internsComments[] - projectId String? - avatarApplicant String? - mentor Profiles? @relation(fields: [mentorId], references: [id], onDelete: SetNull, onUpdate: Cascade) - project Projects? @relation(fields: [projectId], references: [id], onDelete: SetNull, onUpdate: Cascade) - + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + email String @unique + personalEmail String + fullName String + nationality String + country String + dayOfBirth DateTime + homeAddress String + phone String + universityEmail String? + emergencyContactName String? + emergencyContactPhone String? + emergencyRelationship String? + gender String + englishLevel String + universityId String? + university Universities? @relation(fields: [universityId], references: [id], onDelete: Cascade, onUpdate: Cascade) + universityPointOfContactId String? + universityPointOfContact UniversityPointsOfContact? @relation(fields: [universityPointOfContactId], references: [id], onDelete: Cascade, onUpdate: Cascade) + major String + semester String + graduationDate DateTime + interest String + experience String + cvLink String + interestedRoles String? + preferredTools String? + startDate DateTime + endDate DateTime + hoursPerWeek Int + howDidYouHearAboutUs String + participatedAtWizeline Boolean + wizelinePrograms String? + status String @default("DRAFT") + mentorId String? + comments String? + appliedProjects String? + appliedProjectsId String? + generalComments internsComments[] + projectId String? + avatarApplicant String? + mentor Profiles? @relation(fields: [mentorId], references: [id], onDelete: SetNull, onUpdate: Cascade) + project Projects? @relation(fields: [projectId], references: [id], onDelete: SetNull, onUpdate: Cascade) @@index([status], map: "applicant_status_idx") } -model Experience{ - id Int @id @default(autoincrement()) - comentario String - profileId String? - profile Profiles? @relation(fields: [profileId], references: [id], onDelete: SetNull, onUpdate: Cascade) +model Experience { + id Int @id @default(autoincrement()) + comentario String + profileId String? + profile Profiles? @relation(fields: [profileId], references: [id], onDelete: SetNull, onUpdate: Cascade) } model GitHubActivity { - id String @id - typeEvent String - created_at DateTime - author String - avatar_url String - projectId String? - project Projects? @relation(fields: [projectId], references: [id], onDelete: SetNull, onUpdate: Cascade) + id String @id + typeEvent String + created_at DateTime + author String + avatar_url String + projectId String? + project Projects? @relation(fields: [projectId], references: [id], onDelete: SetNull, onUpdate: Cascade) } model GitHubReleases { - id String @id - body String - name String - tagName String - author String - prerealease Boolean - created_at DateTime - projectId String? - link String - project Projects? @relation(fields: [projectId], references: [id], onDelete: SetNull, onUpdate: Cascade) + id String @id + body String + name String + tagName String + author String + prerealease Boolean + created_at DateTime + projectId String? + link String + project Projects? @relation(fields: [projectId], references: [id], onDelete: SetNull, onUpdate: Cascade) } model Universities { - id String @id @default(cuid()) - name String @unique - active Boolean @default(true) - pointsOfContact UniversityPointsOfContact[] - applicants Applicant[] - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id String @id @default(cuid()) + name String @unique + active Boolean @default(true) + pointsOfContact UniversityPointsOfContact[] + applicants Applicant[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } model UniversityPointsOfContact { - id String @id @default(cuid()) - fullName String - active Boolean @default(true) - university Universities? @relation(fields: [universityId], references: [id], onDelete: Cascade, onUpdate: Cascade) - universityId String? - applicants Applicant[] - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id String @id @default(cuid()) + fullName String + active Boolean @default(true) + university Universities? @relation(fields: [universityId], references: [id], onDelete: Cascade, onUpdate: Cascade) + universityId String? + applicants Applicant[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt }