From 7673146a58d2f4a3bf3a283ebba0892183c722e0 Mon Sep 17 00:00:00 2001 From: Aakash Singh <78924853+aakash2330@users.noreply.github.com> Date: Sun, 15 Sep 2024 18:21:54 +0530 Subject: [PATCH] feature * gmaps-dropdown * company-logo-url-fix * workflow-pipeline-prettier-fix * prettier-fix * failure-syntax-fix * ui changes + husky pre-commit * prettier-fix --------- Co-authored-by: Aakash Singh Co-authored-by: Vineet Agarwal <91052168+VineeTagarwaL-code@users.noreply.github.com> --- .env.example | 4 +++ .github/workflows/ci.yaml | 6 +++- package.json | 13 ++++++++- prisma/schema.prisma | 15 ++-------- prisma/seed.ts | 15 ++-------- src/actions/job.action.ts | 28 +++++++++++++++---- src/app/globals.css | 27 ++++++++++++++++++ src/components/all-jobs.tsx | 2 +- src/components/gmaps-autosuggest.tsx | 42 ++++++++++++++++++++++++++++ src/components/job-form.tsx | 24 ++++------------ src/layouts/footer.tsx | 12 ++++---- src/layouts/job-filters.tsx | 30 ++++++++++++++------ src/lib/validators/jobs.validator.ts | 9 +++--- src/services/jobs.services.ts | 4 +-- src/types/jobs.types.ts | 3 +- 15 files changed, 159 insertions(+), 75 deletions(-) create mode 100644 src/components/gmaps-autosuggest.tsx diff --git a/.env.example b/.env.example index c9deb5b8..f8f03c54 100644 --- a/.env.example +++ b/.env.example @@ -15,3 +15,7 @@ NEXTAUTH_URL="http://localhost:3000" CDN_API_KEY=api-key CDN_BASE_UPLOAD_URL=https://sg.storage.bunnycdn.com/job-board/assets CDN_BASE_ACCESS_URL=https://job-board.b-cdn.net/assets + + +NEXT_PUBLIC_GOOGLE_MAPS_API_KEY= + diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 424c68cc..d189e867 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,6 +27,10 @@ jobs: - name: Run format check run: npm run check + + - name: Run format fix if check fails + if: ${{ failure() }} + run: npm run format - name: Run build - run: npm run build \ No newline at end of file + run: npm run build diff --git a/package.json b/package.json index 36636e1b..9ccd4412 100644 --- a/package.json +++ b/package.json @@ -9,16 +9,27 @@ "lint": "next lint", "dev:docker": "npm run db:seed & next dev", "db:seed": "npx prisma db push & npx prisma db seed", - "format": "prettier --write \"**/*.{ts,tsx,js,jsx,md,mdx,css}\"", "check": "prettier --check \"**/*.{ts,tsx,js,jsx,md,mdx,css}\"", + "format": "prettier --write \"**/*.{ts,tsx,js,jsx,md,mdx,css}\"", "prepare": "husky" }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "**/*.{ts,tsx,js,jsx,md,mdx,css}": [ + "prettier --write" + ] + }, "prisma": { "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts" }, "dependencies": { "@aws-sdk/client-s3": "^3.645.0", "@aws-sdk/s3-request-presigner": "^3.645.0", + "@faker-js/faker": "^9.0.0", "@hookform/resolvers": "^3.9.0", "@prisma/client": "5.18.0", "@radix-ui/react-accordion": "^1.2.0", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index baec4f15..e3eba55e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -30,7 +30,8 @@ model Job { type String workMode WorkMode @map("work_mode") currency Currency @default(INR) - location JobLocations + city String + address String application String companyLogo String hasSalaryRange Boolean @default(false) @map("has_salary_range") @@ -58,15 +59,3 @@ enum Role { ADMIN } -enum JobLocations { - BANGLORE - DELHI - MUMBAI - CHENNAI - PUNE - HYDERABAD - KOLKATA - AHMEDABAD - JAIPUR - SURAT -} diff --git a/prisma/seed.ts b/prisma/seed.ts index 347cfcfc..3f01a17b 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,16 +1,14 @@ /* eslint-disable no-console */ import { Currency, Role, WorkMode } from '@prisma/client'; +import { faker } from '@faker-js/faker'; import bcrypt from 'bcryptjs'; import prisma from '../src/config/prisma.config'; -import { JobLocations } from '@prisma/client'; const users = [ { id: '1', name: 'Jack', email: 'user@gmail.com' }, { id: '2', name: 'Admin', email: 'admin@gmail.com', role: Role.ADMIN }, ]; -const locationArr = Object.keys(JobLocations); - let jobs = [ { id: '1', @@ -286,13 +284,6 @@ async function seedUsers() { } async function seedJobs() { - jobs = jobs.map((j, index) => { - return { - ...j, - location: - locationArr[index] !== undefined ? locationArr[index] : locationArr[3], - }; - }); try { await Promise.all( jobs.map(async (j) => @@ -311,8 +302,8 @@ async function seedJobs() { workMode: j.workMode, currency: j.currency, application: j.application, - //@ts-ignore - location: j.location, + city: faker.location.city(), + address: faker.location.streetAddress(), companyLogo: j.companyLogo, hasSalaryRange: j.hasSalaryRange, minSalary: j.minSalary, diff --git a/src/actions/job.action.ts b/src/actions/job.action.ts index 693740fb..3b752977 100644 --- a/src/actions/job.action.ts +++ b/src/actions/job.action.ts @@ -29,7 +29,8 @@ export const createJob = withServerActionAsyncCatcher< type, category, application, - location, + city, + address, companyLogo, title, workMode, @@ -52,7 +53,8 @@ export const createJob = withServerActionAsyncCatcher< hasSalaryRange, minSalary, maxSalary, - location, + city, + address, companyLogo, workMode, isVerifiedJob: false, // Default to false since there's no session to check for admin role @@ -73,8 +75,8 @@ export const getAllJobs = withServerActionAsyncCatcher< if (data?.salaryrange && !Array.isArray(data?.salaryrange)) { data.salaryrange = Array.of(data?.salaryrange); } - if (data?.location && !Array.isArray(data?.location)) { - data.location = Array.of(data?.location); + if (data?.city && !Array.isArray(data?.city)) { + data.city = Array.of(data?.city); } const result = JobQuerySchema.parse(data); const { filterQueries, orderBy, pagination } = getJobFilters(result); @@ -90,7 +92,8 @@ export const getAllJobs = withServerActionAsyncCatcher< title: true, description: true, companyName: true, - location: true, + city: true, + address: true, workMode: true, minSalary: true, maxSalary: true, @@ -131,7 +134,8 @@ export const getJobById = withServerActionAsyncCatcher< companyBio: true, companyEmail: true, companyLogo: true, - location: true, + city: true, + address: true, workMode: true, minSalary: true, maxSalary: true, @@ -142,3 +146,15 @@ export const getJobById = withServerActionAsyncCatcher< job, }).serialize(); }); + +export const getCityFilters = async () => { + const response = await prisma.job.findMany({ + select: { + city: true, + }, + }); + const cities = Array.from(new Set(response.map((res) => res.city))); + return new SuccessResponse(`Cities fetched successfully`, 200, { + cities, + }).serialize(); +}; diff --git a/src/app/globals.css b/src/app/globals.css index b3c421ed..301c0d12 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -345,3 +345,30 @@ overflow-x: hidden !important; /* Allow horizontal scrolling */ overflow-y: hidden !important; /* Hide vertical overflow */ } + +.pac-container { + background-color: black !important; + color: #fff; + border-radius: 8px; + padding-top: 5px; + padding-bottom: 5px; + font-family: '__Inter_36bd41', '__Inter_Fallback', sans-serif !important; + font-size: 14px !important; +} +.pac-item { + color: #fff !important; + border: none; + font-size: 14px; +} +.pac-item:hover { + background-color: hsl(0, 0%, 14.9%) !important; + cursor: pointer; +} +.pac-item-query { + color: white; + font-weight: bold; +} + +.pac-logo.hdpi::after { + content: none; +} diff --git a/src/components/all-jobs.tsx b/src/components/all-jobs.tsx index ce519806..67123e2c 100644 --- a/src/components/all-jobs.tsx +++ b/src/components/all-jobs.tsx @@ -40,7 +40,7 @@ const AllJobs = async ({ searchParams }: PaginatorProps) => {
- {job.location}{' '} + {job.address}{' '} ({job.workMode}) diff --git a/src/components/gmaps-autosuggest.tsx b/src/components/gmaps-autosuggest.tsx new file mode 100644 index 00000000..a13f04ee --- /dev/null +++ b/src/components/gmaps-autosuggest.tsx @@ -0,0 +1,42 @@ +import Script from 'next/script'; +import { Input } from './ui/input'; + +export type TgmapsAddress = { city: string; fullAddress: string }; + +export function GmapsAutocompleteAddress({ form }: { form: any }) { + let autocomplete: any = null; + + function onPlaceChanged() { + const { name, formatted_address } = autocomplete.getPlace(); + form.setValue('city', name); + form.setValue('address', formatted_address); + } + + function initializeGmaps() { + if ((window as any).google) { + autocomplete = new (window as any).google.maps.places.Autocomplete( + document.getElementById('autocomplete'), + { + types: ['(cities)'], + } + ); + autocomplete.addListener('place_changed', onPlaceChanged); + } + } + return ( + <> +