diff --git a/apps/portal/package.json b/apps/portal/package.json index cda1ec4e..fb8b60b9 100644 --- a/apps/portal/package.json +++ b/apps/portal/package.json @@ -43,7 +43,6 @@ "react-query": "^3.39.2", "read-excel-file": "^5.5.3", "superjson": "^1.10.0", - "xlsx": "^0.18.5", "unique-names-generator": "^4.7.1", "xlsx": "^0.18.5", "zod": "^3.18.0" diff --git a/apps/portal/prisma/migrations/20221104095551_use_location_database_for_resumes/migration.sql b/apps/portal/prisma/migrations/20221104095551_use_location_database_for_resumes/migration.sql new file mode 100644 index 00000000..e9bda081 --- /dev/null +++ b/apps/portal/prisma/migrations/20221104095551_use_location_database_for_resumes/migration.sql @@ -0,0 +1,13 @@ +/* + Warnings: + + - You are about to drop the column `location` on the `ResumesResume` table. All the data in the column will be lost. + - Added the required column `locationId` to the `ResumesResume` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable. Set default location to Singapore. +ALTER TABLE "ResumesResume" DROP COLUMN "location", +ADD COLUMN "locationId" TEXT NOT NULL DEFAULT '196'; + +-- AddForeignKey +ALTER TABLE "ResumesResume" ADD CONSTRAINT "ResumesResume_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "Country"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/portal/prisma/migrations/20221105140124_revert_default_location/migration.sql b/apps/portal/prisma/migrations/20221105140124_revert_default_location/migration.sql new file mode 100644 index 00000000..63805097 --- /dev/null +++ b/apps/portal/prisma/migrations/20221105140124_revert_default_location/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "ResumesResume" ALTER COLUMN "locationId" DROP DEFAULT; diff --git a/apps/portal/prisma/migrations/20221106002645_country_ranking/migration.sql b/apps/portal/prisma/migrations/20221106002645_country_ranking/migration.sql new file mode 100644 index 00000000..c5a989d9 --- /dev/null +++ b/apps/portal/prisma/migrations/20221106002645_country_ranking/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Country" ADD COLUMN "ranking" INTEGER DEFAULT 0; diff --git a/apps/portal/prisma/schema.prisma b/apps/portal/prisma/schema.prisma index 662a321c..b7264b71 100644 --- a/apps/portal/prisma/schema.prisma +++ b/apps/portal/prisma/schema.prisma @@ -110,8 +110,11 @@ model Country { id String @id name String @unique code String @unique + // The higher the value of the ranking, the higher it appears in the search results. + ranking Int? @default(0) states State[] questionsQuestionEncounters QuestionsQuestionEncounter[] + ResumesResume ResumesResume[] } model State { @@ -148,13 +151,14 @@ model ResumesResume { // TODO: Update role, experience, location to use Enums role String @db.Text experience String @db.Text - location String @db.Text + locationId String url String additionalInfo String? @db.Text isResolved Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) + location Country @relation(fields: [locationId], references: [id], onDelete: Cascade) stars ResumesStar[] comments ResumesComment[] } diff --git a/apps/portal/public/team/ai-ling.jpg b/apps/portal/public/team/ai-ling.jpg new file mode 100644 index 00000000..d74397d2 Binary files /dev/null and b/apps/portal/public/team/ai-ling.jpg differ diff --git a/apps/portal/public/team/bryann.jpg b/apps/portal/public/team/bryann.jpg new file mode 100644 index 00000000..2cdad4d1 Binary files /dev/null and b/apps/portal/public/team/bryann.jpg differ diff --git a/apps/portal/public/team/stuart.jpg b/apps/portal/public/team/stuart.jpg new file mode 100644 index 00000000..935436e0 Binary files /dev/null and b/apps/portal/public/team/stuart.jpg differ diff --git a/apps/portal/public/team/ziqing.jpg b/apps/portal/public/team/ziqing.jpg new file mode 100644 index 00000000..3c75db43 Binary files /dev/null and b/apps/portal/public/team/ziqing.jpg differ diff --git a/apps/portal/src/components/offers/OffersNavigation.tsx b/apps/portal/src/components/offers/OffersNavigation.tsx index 315bac9f..cf4b8e1f 100644 --- a/apps/portal/src/components/offers/OffersNavigation.tsx +++ b/apps/portal/src/components/offers/OffersNavigation.tsx @@ -3,12 +3,14 @@ import type { ProductNavigationItems } from '~/components/global/ProductNavigati const navigation: ProductNavigationItems = [ { href: '/offers/submit', name: 'Analyze your offers' }, { href: '/offers/features', name: 'Features' }, + { href: '/offers/about', name: 'About' }, ]; const navigationAuthenticated: ProductNavigationItems = [ { href: '/offers/submit', name: 'Analyze your offers' }, { href: '/offers/dashboard', name: 'Your dashboard' }, { href: '/offers/features', name: 'Features' }, + { href: '/offers/about', name: 'About' }, ]; const config = { diff --git a/apps/portal/src/components/offers/constants.ts b/apps/portal/src/components/offers/constants.ts index 48d9bf48..0dc44da5 100644 --- a/apps/portal/src/components/offers/constants.ts +++ b/apps/portal/src/components/offers/constants.ts @@ -1,4 +1,5 @@ export const HOME_URL = '/offers'; +export const OFFERS_SUBMIT_URL = '/offers/submit'; export const JobTypeLabel = { FULLTIME: 'Full-time', @@ -37,4 +38,4 @@ export const profileDetailTabs = [ label: ProfileDetailTab.ANALYSIS, value: ProfileDetailTab.ANALYSIS, }, -]; \ No newline at end of file +]; diff --git a/apps/portal/src/components/offers/features/LeftTextCard.tsx b/apps/portal/src/components/offers/features/LeftTextCard.tsx index 867b24b7..1e514732 100644 --- a/apps/portal/src/components/offers/features/LeftTextCard.tsx +++ b/apps/portal/src/components/offers/features/LeftTextCard.tsx @@ -2,14 +2,14 @@ import type { StaticImageData } from 'next/image'; import Image from 'next/image'; import type { ReactNode } from 'react'; -import { HOME_URL } from '../constants'; - type LeftTextCardProps = Readonly<{ + buttonLabel: string; description: string; icon: ReactNode; imageAlt: string; imageSrc: StaticImageData; title: string; + url: string; }>; export default function LeftTextCard({ @@ -18,6 +18,8 @@ export default function LeftTextCard({ imageAlt, imageSrc, title, + buttonLabel, + url, }: LeftTextCardProps) { return (
@@ -36,8 +38,8 @@ export default function LeftTextCard({
- Get started + href={url}> + {buttonLabel}
diff --git a/apps/portal/src/components/offers/features/RightTextCard.tsx b/apps/portal/src/components/offers/features/RightTextCard.tsx index 028dc57b..5c9e10a0 100644 --- a/apps/portal/src/components/offers/features/RightTextCard.tsx +++ b/apps/portal/src/components/offers/features/RightTextCard.tsx @@ -2,14 +2,14 @@ import type { StaticImageData } from 'next/image'; import Image from 'next/image'; import type { ReactNode } from 'react'; -import { HOME_URL } from '../constants'; - type RightTextCarddProps = Readonly<{ + buttonLabel: string; description: string; icon: ReactNode; imageAlt: string; imageSrc: StaticImageData; title: string; + url: string; }>; export default function RightTextCard({ @@ -18,6 +18,8 @@ export default function RightTextCard({ imageAlt, imageSrc, title, + url, + buttonLabel, }: RightTextCarddProps) { return (
@@ -36,8 +38,8 @@ export default function RightTextCard({
- Get started + href={url}> + {buttonLabel}
diff --git a/apps/portal/src/components/offers/features/images/offers-analysis.png b/apps/portal/src/components/offers/features/images/offers-analysis.png index 896c23f7..2af9ad70 100644 Binary files a/apps/portal/src/components/offers/features/images/offers-analysis.png and b/apps/portal/src/components/offers/features/images/offers-analysis.png differ diff --git a/apps/portal/src/components/offers/features/images/offers-browse.png b/apps/portal/src/components/offers/features/images/offers-browse.png index 09968721..2ef03f68 100644 Binary files a/apps/portal/src/components/offers/features/images/offers-browse.png and b/apps/portal/src/components/offers/features/images/offers-browse.png differ diff --git a/apps/portal/src/components/offers/features/images/offers-profile.png b/apps/portal/src/components/offers/features/images/offers-profile.png index e47af859..ad0308a1 100644 Binary files a/apps/portal/src/components/offers/features/images/offers-profile.png and b/apps/portal/src/components/offers/features/images/offers-profile.png differ diff --git a/apps/portal/src/components/offers/forms/FormJobTitlesTypeahead.tsx b/apps/portal/src/components/offers/forms/FormJobTitlesTypeahead.tsx index fa35d320..bffe93b8 100644 --- a/apps/portal/src/components/offers/forms/FormJobTitlesTypeahead.tsx +++ b/apps/portal/src/components/offers/forms/FormJobTitlesTypeahead.tsx @@ -3,7 +3,7 @@ import { useFormContext, useWatch } from 'react-hook-form'; import type { JobTitleType } from '~/components/shared/JobTitles'; import { getLabelForJobTitleType } from '~/components/shared/JobTitles'; -import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead'; +import JobTitlesTypeahead from '~/components/shared/JobTitlesTypeahead'; type Props = Omit< ComponentProps, @@ -21,11 +21,15 @@ export default function FormJobTitlesTypeahead({ name, ...props }: Props) { return ( { setValue(name, option?.value); }} diff --git a/apps/portal/src/components/offers/table/OffersTable.tsx b/apps/portal/src/components/offers/table/OffersTable.tsx index 532946a8..b200380b 100644 --- a/apps/portal/src/components/offers/table/OffersTable.tsx +++ b/apps/portal/src/components/offers/table/OffersTable.tsx @@ -275,7 +275,7 @@ export default function OffersTable({ {!offers || (offers.length === 0 && (
-
No data yet🥺
+
No data yet 🥺
))} @@ -290,4 +290,4 @@ export default function OffersTable({ /> ); -} \ No newline at end of file +} diff --git a/apps/portal/src/components/questions/AddToListDropdown.tsx b/apps/portal/src/components/questions/AddToListDropdown.tsx index 86aa72d2..c26bcb1c 100644 --- a/apps/portal/src/components/questions/AddToListDropdown.tsx +++ b/apps/portal/src/components/questions/AddToListDropdown.tsx @@ -3,26 +3,52 @@ import type { PropsWithChildren } from 'react'; import { useMemo } from 'react'; import { Fragment, useRef, useState } from 'react'; import { Menu, Transition } from '@headlessui/react'; -import { CheckIcon, HeartIcon } from '@heroicons/react/20/solid'; - -import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics'; +import { CheckIcon, HeartIcon, PlusIcon } from '@heroicons/react/20/solid'; +import { + useAddQuestionToListAsync, + useCreateListAsync, + useRemoveQuestionFromListAsync, +} from '~/utils/questions/mutations'; import { useProtectedCallback } from '~/utils/questions/useProtectedCallback'; import { trpc } from '~/utils/trpc'; +import CreateListDialog from './CreateListDialog'; + export type AddToListDropdownProps = { questionId: string; }; +export type DropdownButtonProps = PropsWithChildren<{ + onClick: () => void; +}>; + +function DropdownButton({ onClick, children }: DropdownButtonProps) { + return ( + + {({ active }) => ( + + )} + + ); +} + export default function AddToListDropdown({ questionId, }: AddToListDropdownProps) { - const { event } = useGoogleAnalytics(); - const [menuOpened, setMenuOpened] = useState(false); const ref = useRef(null); + const [show, setShow] = useState(false); - const utils = trpc.useContext(); + const createListAsync = useCreateListAsync(); const { data: lists } = trpc.useQuery(['questions.lists.getListsByUser']); const listsWithQuestionData = useMemo(() => { @@ -34,30 +60,8 @@ export default function AddToListDropdown({ })); }, [lists, questionId]); - const { mutateAsync: addQuestionToList } = trpc.useMutation( - 'questions.lists.createQuestionEntry', - { - // TODO: Add optimistic update - onSuccess: () => { - utils.invalidateQueries(['questions.lists.getListsByUser']); - event({ - action: 'questions.lists', - category: 'engagement', - label: 'add question to list', - }); - }, - }, - ); - - const { mutateAsync: removeQuestionFromList } = trpc.useMutation( - 'questions.lists.deleteQuestionEntry', - { - // TODO: Add optimistic update - onSuccess: () => { - utils.invalidateQueries(['questions.lists.getListsByUser']); - }, - }, - ); + const addQuestionToList = useAddQuestionToListAsync(); + const removeQuestionFromList = useRemoveQuestionFromListAsync(); const addClickOutsideListener = () => { document.addEventListener('click', handleClickOutside, true); @@ -110,63 +114,79 @@ export default function AddToListDropdown({ ); return ( - -
- - -
- - - - {menuOpened && ( - <> - {(listsWithQuestionData ?? []).map((list) => ( -
- - {({ active }) => ( - - )} - -
- ))} - - )} -
-
-
+ + + + ))} + { + setShow(true); + }}> + + + )} + + + + { + setShow(false); + }} + onSubmit={async (data) => { + await createListAsync(data); + setShow(false); + }} + /> + ); } diff --git a/apps/portal/src/components/questions/AnswerCommentListItem.tsx b/apps/portal/src/components/questions/AnswerCommentListItem.tsx index c65a379f..a51cd291 100644 --- a/apps/portal/src/components/questions/AnswerCommentListItem.tsx +++ b/apps/portal/src/components/questions/AnswerCommentListItem.tsx @@ -25,7 +25,7 @@ export default function AnswerCommentListItem({ useAnswerCommentVote(answerCommentId); return ( -
+