Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Konstantin/rka 51 ashby #14

Merged
merged 4 commits into from
Jul 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion app/add/components/variant/variants/url.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { HiringPlatformName } from '@/lib/db/schema'
import { normalizeURL } from '@/lib/utils/normalize-url'
import { zodResolver } from '@hookform/resolvers/zod'
import { CheckIcon, MagnifyingGlassIcon } from '@radix-ui/react-icons'
Expand All @@ -21,6 +22,11 @@ const schema = z.object({
url: z.string().min(1, 'URL must not be empty').url(),
})

const platformLogo: Record<HiringPlatformName, string> = {
ashby: 'ashby.png',
greenhouse: 'greenhouse.svg',
}

type FormType = z.infer<typeof schema>

export const VariantURL = () => {
Expand Down Expand Up @@ -104,7 +110,7 @@ export const VariantURL = () => {
<Card>
<Flex gap="3" align="center">
<Image
src={`/hiring-platforms/${platform.toLowerCase()}.svg`}
src={`/hiring-platforms/${platformLogo[platform]}`}
alt={`${platform} logo`}
width="32"
height="32"
Expand Down
7 changes: 7 additions & 0 deletions app/api/companies/process/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createPlatform } from '@/lib/hiring-platforms/registry'

import { logger } from '@/lib/logger'
import type { NonNullableProperty } from '@/lib/types/utils'
import { waitFor } from '@/lib/utils/wait-for'
import { ReasonPhrases, StatusCodes } from 'http-status-codes'
import { headers } from 'next/headers'

Expand Down Expand Up @@ -77,5 +78,11 @@ export const GET = async () => {
status: StatusCodes.INTERNAL_SERVER_ERROR,
},
)
} finally {
logger.info('Finished `job-processing` cron job')
logger.flush()

// TODO: vercel edge functions finish too quick, before the logger flushes
await waitFor(1000)
}
}
13 changes: 4 additions & 9 deletions app/api/email/jobs/route.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import Jobs from '@/emails/jobs'
import { queryGetJobs } from '@/lib/db/queries'
import { logger } from '@/lib/logger'
import { waitFor } from '@/lib/utils/wait-for'
import { render } from '@react-email/render'
import { ReasonPhrases, StatusCodes } from 'http-status-codes'
import { headers } from 'next/headers'
import { Resend } from 'resend'

const resend = new Resend(process.env.RESEND_API_KEY)

const delay = (ms: number) => {
return new Promise(resolve => setTimeout(resolve, ms))
}

export const GET = async () => {
try {
logger.info('Starting `send-email` cron job')
Expand Down Expand Up @@ -67,11 +64,9 @@ export const GET = async () => {
)
} finally {
logger.info('Finished `send-email` cron job')
logger.flush()

logger.flush(() => {
console.log('Logger flushed')
})

await delay(1000)
// TODO: vercel edge functions finish too quick, before the logger flushes
await waitFor(1000)
}
}
2 changes: 2 additions & 0 deletions app/components/list/actions/mark-property.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use server'
import {
queryMarkApplied,
queryMarkHidden,
queryMarkSeen,
queryMarkTopChoice,
Expand All @@ -9,3 +10,4 @@ import { createAction } from './create-action'
export const actionMarkTopChoice = createAction(queryMarkTopChoice)
export const actionMarkHidden = createAction(queryMarkHidden)
export const actionMarkSeen = createAction(queryMarkSeen)
export const actionMarkApplied = createAction(queryMarkApplied)
109 changes: 18 additions & 91 deletions app/components/list/filter-panel.tsx
Original file line number Diff line number Diff line change
@@ -1,100 +1,27 @@
'use client'

import type { GetJobsFilter } from '@/lib/db/queries'
import { Button, Flex, Reset } from '@radix-ui/themes'
import Link from 'next/link'
import { usePathname, useSearchParams } from 'next/navigation'
import { useCallback } from 'react'

const FilterButton = ({
searchParams,
title,
active = false,
}: { searchParams: string; title: string; active?: boolean }) => {
const pathname = usePathname()

return (
<Link href={`${pathname}?${searchParams}`}>
<Button variant={active ? 'solid' : 'outline'}>{title}</Button>
</Link>
)
}
import { SegmentedControl } from '@radix-ui/themes'
import { usePathname, useRouter } from 'next/navigation'

export const FilterPanel = () => {
const searchParams = useSearchParams()

const createSearchParams = useCallback(
(filter: GetJobsFilter, shouldReset = filter === 'all') => {
const newSearchParams = new URLSearchParams(searchParams)

const shouldRemove = newSearchParams
.getAll('filter')
.some(existingFilter => existingFilter === filter)

if (!newSearchParams.has('filter')) {
newSearchParams.set('filter', 'new')
}

if (shouldRemove) {
newSearchParams.delete('filter', filter)
} else if (shouldReset) {
newSearchParams.set('filter', filter)
} else {
newSearchParams.delete('filter', 'all')
newSearchParams.append('filter', filter)
}
const pathname = usePathname()
const { push } = useRouter()

newSearchParams.delete('page')
const handleValueChange = (value: string) => {
const searchParams = new URLSearchParams({ filter: value })

return newSearchParams.toString()
},
[searchParams],
)
push(`${pathname}?${searchParams}`)
}

return (
<Flex gap="3" asChild>
<Reset>
<ul>
<li>
<FilterButton
title="New / Unseen"
searchParams={createSearchParams('new')}
active={
searchParams.getAll('filter').includes('new') ||
!searchParams.has('filter')
}
/>
</li>
<li>
<FilterButton
title="Top Choice"
searchParams={createSearchParams('topChoice')}
active={searchParams.getAll('filter').includes('topChoice')}
/>
</li>
<li>
<FilterButton
title="Seen"
searchParams={createSearchParams('seen')}
active={searchParams.getAll('filter').includes('seen')}
/>
</li>
<li>
<FilterButton
title="Hidden"
searchParams={createSearchParams('hidden')}
active={searchParams.getAll('filter').includes('hidden')}
/>
</li>
<li>
<FilterButton
title="All"
searchParams={createSearchParams('all')}
active={searchParams.getAll('filter').includes('all')}
/>
</li>
</ul>
</Reset>
</Flex>
<SegmentedControl.Root onValueChange={handleValueChange} defaultValue="new">
<SegmentedControl.Item value="new">New / Unseen</SegmentedControl.Item>
<SegmentedControl.Item value="topChoice">
Top Choice
</SegmentedControl.Item>
<SegmentedControl.Item value="seen">Seen</SegmentedControl.Item>
<SegmentedControl.Item value="hidden">Hidden</SegmentedControl.Item>
<SegmentedControl.Item value="applied">Applied</SegmentedControl.Item>
<SegmentedControl.Item value="all">All</SegmentedControl.Item>
</SegmentedControl.Root>
)
}
11 changes: 11 additions & 0 deletions app/components/list/job-card-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import {
EyeNoneIcon,
EyeOpenIcon,
LightningBoltIcon,
RocketIcon,
} from '@radix-ui/react-icons'
import { Text } from '@radix-ui/themes'
import { ActionButton } from './action-button'
import {
actionMarkApplied,
actionMarkHidden,
actionMarkSeen,
actionMarkTopChoice,
Expand All @@ -18,6 +20,7 @@ export const JobCardActions = ({ job }: { job: SelectJob }) => {
const hidden = useJobAction(job.isHidden, actionMarkHidden)
const topChoice = useJobAction(job.isTopChoice, actionMarkTopChoice)
const seen = useJobAction(job.isSeen, actionMarkSeen)
const applied = useJobAction(job.isApplied, actionMarkApplied)

return (
<>
Expand Down Expand Up @@ -48,6 +51,14 @@ export const JobCardActions = ({ job }: { job: SelectJob }) => {
icon={<EyeOpenIcon />}
label="Seen"
/>
<ActionButton
isActive={applied.isActive}
loading={applied.loading}
clickHandler={() => applied.clickHandler(job.id)}
colorActive="pink"
icon={<RocketIcon />}
label="Applied"
/>
</>
)
}
15 changes: 10 additions & 5 deletions app/components/list/job-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,16 @@ export const JobCard = async ({ job }: JobCardProps) => {
}).format(new Date(job.lastUpdatedAt))}
</Text>
</Flex>
{isAdmin(user) && (
<Flex align="center" gridColumn="1/-1" gap="2" justify="end">
<JobCardActions job={job} />
</Flex>
)}
<Flex justify="between" gridColumn="1/-1">
<Text size="2" color="gray">
{job.compensationSummary}
</Text>
{isAdmin(user) && (
<Flex align="center" gap="2" justify="between">
<JobCardActions job={job} />
</Flex>
)}
</Flex>
</Grid>
</Card>
)
Expand Down
38 changes: 26 additions & 12 deletions app/components/list/job-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { type GetJobsFilter, queryGetJobs } from '@/lib/db/queries'
import { JobCard } from './job-card'

import type { PageSearchParams } from '@/app/types'
import { Flex, Reset } from '@radix-ui/themes'
import { ValueIcon } from '@radix-ui/react-icons'
import { Callout, Flex, Reset } from '@radix-ui/themes'
import { FilterPanel } from './filter-panel'
import { Pagination } from './pagination'

Expand All @@ -17,22 +18,35 @@ export const JobList = async ({ searchParams }: JobListProps) => {
searchParams.page ? Number(searchParams.page) : 1,
)

const hasJobs = result.data.length > 0

return (
<Flex direction="column" gap="3">
<FilterPanel />
<Flex asChild direction="column" gap="3">
<Reset>
{/* biome-ignore lint/a11y/noRedundantRoles: safari 👀 */}
<ul role="list">
{result.data.map(job => (
<li key={job.id}>
<JobCard job={job} />
</li>
))}
</ul>
</Reset>
{hasJobs ? (
<Reset>
{/* biome-ignore lint/a11y/noRedundantRoles: safari 👀 */}
<ul role="list">
{result.data.map(job => (
<li key={job.id}>
<JobCard job={job} />
</li>
))}
</ul>
</Reset>
) : (
<Callout.Root size="3">
<Callout.Icon>
<ValueIcon />
</Callout.Icon>
<Callout.Text>
No jobs found. Try changing the filters.
</Callout.Text>
</Callout.Root>
)}
</Flex>
<Pagination total={result.total} />
{hasJobs ? <Pagination total={result.total} /> : null}
</Flex>
)
}
1 change: 1 addition & 0 deletions drizzle/0008_plain_midnight.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TYPE "hiring_platform" ADD VALUE 'ashby';
25 changes: 25 additions & 0 deletions drizzle/0009_strong_mariko_yashida.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
DO $$ BEGIN
CREATE TYPE "public"."compensation_type" AS ENUM('salary', 'equity');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "compensations" (
"id" serial PRIMARY KEY NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"job_id" integer NOT NULL,
"type" "compensation_type" NOT NULL,
"currency_code" text,
"min_value" numeric(10, 3) NOT NULL,
"max_value" numeric(10, 3),
"summary" text,
"interval" text
);
--> statement-breakpoint
ALTER TABLE "jobs" ADD COLUMN "is_remote" boolean;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "compensations" ADD CONSTRAINT "compensations_job_id_jobs_id_fk" FOREIGN KEY ("job_id") REFERENCES "public"."jobs"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
8 changes: 8 additions & 0 deletions drizzle/0010_silly_joseph.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DROP TABLE "compensations";--> statement-breakpoint
ALTER TABLE "jobs" ADD COLUMN "currency_code" text;--> statement-breakpoint
ALTER TABLE "jobs" ADD COLUMN "compensation_interval" text;--> statement-breakpoint
ALTER TABLE "jobs" ADD COLUMN "compensation_summary" text;--> statement-breakpoint
ALTER TABLE "jobs" ADD COLUMN "salary_min" numeric(10, 3);--> statement-breakpoint
ALTER TABLE "jobs" ADD COLUMN "salary_max" numeric(10, 3);--> statement-breakpoint
ALTER TABLE "jobs" ADD COLUMN "equity_min" numeric(10, 3);--> statement-breakpoint
ALTER TABLE "jobs" ADD COLUMN "equity_max" numeric(10, 3);
Loading