Merged
267 changes: 267 additions & 0 deletions app/(app)/jobs/create/_client.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
"use client";

import { Button } from "@/components/ui-components/button";
import {
Checkbox,
CheckboxField,
CheckboxGroup,
} from "@/components/ui-components/checkbox";
import { Divider } from "@/components/ui-components/divider";
import { Description, Field, Label } from "@/components/ui-components/fieldset";
import { Heading, Subheading } from "@/components/ui-components/heading";
import { Input } from "@/components/ui-components/input";
import {
Radio,
RadioField,
RadioGroup,
} from "@/components/ui-components/radio";
import { Strong, Text } from "@/components/ui-components/text";
import { Textarea } from "@/components/ui-components/textarea";
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
import Image from "next/image";
import { notFound } from "next/navigation";
import React, { useRef, useState } from "react";

export default function Content() {
const flagEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
const fileInputRef = useRef<HTMLInputElement>(null);
const [imgUrl, setImgUrl] = useState<string | null>(null);

if (!flagEnabled) {
notFound();
}

return (
<form className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
<Heading level={1}>Post a job</Heading>
<Divider className="my-10 mt-6" />
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Logo</Subheading>
<Text>Square format is best</Text>
</div>
<Field>
<div className="flex items-center space-x-4">
<Image

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin A placeholder will be shown if no url is present

src={imgUrl || "/images/company_placeholder.png"}
width={80}
height={80}
alt="Company Logo"
className="rounded-[10px]"
/>
<div>
<Button
color="dark/white"
className="mt-3 rounded-md"
onClick={() => {
fileInputRef.current?.click();
}}
>
Change Logo
</Button>
<Input
type="file"
id="file-input"
name="company-logo"
accept="image/png, image/gif, image/jpeg"
onChange={() => {}}
className="hidden"
ref={fileInputRef}
/>
<Text className="mt-1 text-xs text-gray-500">
JPG, GIF or PNG. 1MB max.
</Text>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a grey square as a placeholder for the image which will be uploaded.
Otherwise there will be layout shift when an image is added.

We need to be able to see the preview of the image to be uploaded. This preview only needs to be in state. Have a look at the settings page for an example of how this is handled.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin Sure will do that way

</div>
</div>
</Field>
</section>
Comment on lines +34 to +77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement file upload functionality and validation.

The structure for the company logo upload is good, but there are a few improvements needed:

  1. The onChange handler for the file input is empty. Implement logic to handle file selection and update the image preview.
  2. Add validation for file type (JPG, GIF, PNG) and size (1MB max) as mentioned in the UI text.
  3. Update the image preview when a new file is selected.

Here's a suggested implementation:

consthandleFileChange=(event: React.ChangeEvent<HTMLInputElement>)=>{constfile=event.target.files?.[0];if(file){if(file.size>1024*1024){alert('File size should not exceed 1MB');return;}if(!['image/jpeg','image/gif','image/png'].includes(file.type)){alert('Only JPG, GIF, or PNG files are allowed');return;}constreader=newFileReader();reader.onload=(e)=>setImgUrl(e.target?.resultasstring);reader.readAsDataURL(file);}};// Update the Input component:<Inputtype="file"id="file-input"name="company-logo"accept="image/png, image/gif, image/jpeg"onChange={handleFileChange}className="hidden"ref={fileInputRef}/>


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Name</Subheading>
<Text>This will be shown in the format you type it</Text>
</div>
<Field>
<Input
id="company-name"
type="text"
placeholder="Pixel Pulse Studios"
autoComplete="given-company-name"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +95

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for company name.

The structure for the company name section is good, but consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register,formState: { errors }}=useForm();// Update the Input component:<Inputid="company-name"type="text"placeholder="Pixel Pulse Studios"autoComplete="given-company-name"{...register("companyName",{required: "Company name is required"})}/>{errors.companyName&&<span>{errors.companyName.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Title</Subheading>
<Text>The job title for the position that you are opening</Text>
</div>
<Field>
<Input
id="job-title"
type="text"
placeholder="Reality Architect"
autoComplete="given-job-title"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +113

@coderabbitaicoderabbitaiBotOct 12, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation.

The structure for company name and job title sections is consistent and well-organized. However, consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register, handleSubmit,formState: { errors }}=useForm();// In the JSX:<Input{...register("companyName",{required: "Company name is required"})}placeholder="Pixel Pulse Studios"/>{errors.companyName&&<span>{errors.companyName.message}</span>}<Input{...register("jobTitle",{required: "Job title is required"})}placeholder="Reality Architect"/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nil2000 I just noticed that we have no validation on the inputs. Would you add this to the list or would you rather if we merged this and you can do it as a next PR so it doesn't get stale.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NiallJoeMaher Considering Hacktoberfest It would be good for me to have a next PR and you can directly assign that to me 😅

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also love to progress with the other follow up issues mentioned in this issue

Comment on lines +97 to +113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for job title.

Similar to the company name section, implement form state management and validation for the job title. Using the same approach with react-hook-form:

// Update the Input component:<Inputid="job-title"type="text"placeholder="Reality Architect"autoComplete="given-job-title"{...register("jobTitle",{required: "Job title is required"})}/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide consistent form handling across the form fields.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Description</Subheading>
<Text>In markdown format</Text>
</div>
<Field>
<Textarea
id="job-description"
placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."
resizable={false}
rows={3}
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance job description input and implement validation.

  1. Implement form state management and validation for the job description, similar to previous sections.
  2. Consider making the textarea resizable or adjustable to accommodate longer job descriptions.

Here's an example implementation:

<Textareaid="job-description"placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."resizable={true}rows={3}{...register("jobDescription",{required: "Job description is required",minLength: {value: 50,message: "Job description should be at least 50 characters long"}})}/>{errors.jobDescription&&<span>{errors.jobDescription.message}</span>}

This allows for resizable input and adds minimum length validation.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Locations</Subheading>
<Text>
Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”).
</Text>
</div>
<Field>
<Input placeholder="Dublin (2 days in the office per week)" />
<CheckboxGroup className="mt-3">
<CheckboxField>
<Checkbox name="remote" value="is_remote" />
<Label>Work is remote</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="relocation" value="is_relocation_package" />
<Label>Relocation package given</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="visa" value="is_visa_sponsored" />
<Label>Visa sponsorship provided</Label>
</CheckboxField>
</CheckboxGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

The job description section looks good, but the locations section could be improved:

  1. Implement state management for the checkboxes.
  2. Consider allowing multiple location inputs or using a more structured approach for location data.
  3. Add validation for the location input.

Here's an example of how you could improve this section:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index,value)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex-1"><divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div></div>

This implementation allows for multiple locations and manages the state of the checkboxes.

Comment on lines +133 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

Consider the following improvements:

  1. Implement state management for the location input and checkboxes.
  2. Allow for multiple location inputs.
  3. Add validation for the location input.

Here's an example implementation:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index: number,value: string)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div>

This implementation allows for multiple locations and manages the state of the checkboxes.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Application form URL</Subheading>
<Text>A link to your website (optional)</Text>
</div>
<Field>
<Input
id="app-url"
type="text"
autoComplete="url"
placeholder="https://example.com"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and state management for application form URL.

Add URL validation and state management for the application form URL input. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');constvalidateUrl=(url: string)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// Update the Input component:<Inputid="app-url"type="text"autoComplete="url"placeholder="https://example.com"value={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){// Handle invalid URL (e.g., show an error message)}}}/>

This implementation includes URL validation and manages the state of the application URL input.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Type</Subheading>
<Text>Full-time, part-time or freelancer</Text>
</div>
<Field>
<RadioGroup defaultValue="full_time">
<RadioField>
<Radio value="full_time" />
<Label>Full-time (€150)</Label>
<Description>Salaried Position</Description>
</RadioField>
<RadioField>
<Radio value="part_time" />
<Label>Part-time (€100)</Label>
<Description>
Salaried position but less than 4 days per week
</Description>
</RadioField>
<RadioField>
<Radio value="freelancer" />
<Label>Freelancer (€100)</Label>
<Description>Shorter-term usually or fixed term/job</Description>
</RadioField>
<RadioField>
<Radio value="other_role_type" />
<Label>Other (€100)</Label>
<Description>
Looking for a co-founder or something else we haven’t thought of
</Description>
</RadioField>
</RadioGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and radio button state management.

The structure of these sections is good, but consider the following improvements:

  1. Add URL validation for the application form URL input.
  2. Implement state management for the job type radio buttons.

Here's an example of how you could improve these sections:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');const[jobType,setJobType]=useState('full_time');constvalidateUrl=(url)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// In the JSX:<Inputvalue={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){alert('Please enter a valid URL');}}}/><RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation includes URL validation and manages the state of the job type selection.

Comment on lines +180 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement state management for job type selection.

Add state management for the job type radio buttons. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[jobType,setJobType]=useState('full_time');// Update the RadioGroup component:<RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation manages the state of the job type selection, allowing you to easily access the selected job type when submitting the form.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Terms & Conditions</Subheading>
<Text>Ah yes, the fine print.</Text>
</div>
<div className="space-y-2">
<Text>
By submitting this job listing, I acknowledge and agree to the
following terms:
</Text>
<Text>
<Strong>Content Restrictions:</Strong> My listing must not contain:{" "}
<br />- Adult or explicit content <br />- Fraudulent or illegitimate
work opportunities <br />- Inappropriate or offensive language
</Text>
<Text>
<Strong>Accurate Classification: </Strong>I confirm that the job
type (e.g., full-time, part-time, freelance) is correctly
categorized.
</Text>
<Text>
<Strong>Removal Policy:</Strong> I understand that my listing may be
removed without notice if it violates any of the above conditions.
</Text>
<Text>
<Strong>Refund Policy:</Strong> If my listing is removed due to a
violation within 7 days of posting, I may be eligible for a refund,
subject to review.
</Text>
<Text>
<Strong>Compliance:</Strong> I agree to comply with all applicable
laws and regulations regarding job postings and employment
practices.
</Text>
</div>
{/* Add error part after validation here */}
</section>
Comment on lines +218 to +256

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add a checkbox for terms and conditions acceptance.

To ensure users explicitly agree to the terms and conditions, add a checkbox at the end of this section. Here's an example implementation:

import{useState}from'react';// Inside the component:const[termsAccepted,setTermsAccepted]=useState(false);// After the terms and conditions text, add:<CheckboxField><Checkboxname="terms"checked={termsAccepted}onChange={(e)=>setTermsAccepted(e.target.checked)}/><Label>Ihavereadandagreetothetermsandconditions</Label></CheckboxField>

Then, in your form submission logic, you can check if termsAccepted is true before allowing the form to be submitted.


<Divider className="my-10" soft />

<div className="flex justify-end">
<Button className="rounded-md" color="pink">
Submit and checkout
</Button>
</div>
</form>
);
Comment on lines +258 to +266

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement form submission and checkout logic.

The submit button is correctly implemented, but there's no form submission or checkout logic. Consider the following improvements:

  1. Implement form validation before submission.
  2. Add error handling for the submission process.
  3. Integrate with a payment gateway for the checkout process.

Here's a basic example of how you could start implementing this:

import{useState}from'react';// Inside the component:const[isSubmitting,setIsSubmitting]=useState(false);consthandleSubmit=async(event: React.FormEvent)=>{event.preventDefault();setIsSubmitting(true);// Perform form validation heretry{// Submit form data to your APIconstresponse=awaitfetch('/api/job-postings',{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(formData),});if(!response.ok)thrownewError('Submission failed');// If submission is successful, proceed to checkout// Integrate with your payment gateway here// For example, redirect to a Stripe checkout pagewindow.location.href='/checkout';}catch(error){console.error('Error:',error);alert('An error occurred. Please try again.');}finally{setIsSubmitting(false);}};// Update the Button component:<ButtonclassName="rounded-md"color="pink"onClick={handleSubmit}disabled={isSubmitting}>{isSubmitting ? 'Submitting...' : 'Submit and checkout'}</Button>

This implementation includes basic form submission logic and error handling. You'll need to replace the placeholder API call and checkout process with your actual implementation.

}
7 changes: 7 additions & 0 deletions app/(app)/jobs/create/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
import Content from "./_client";

function page() {
return <Content />;
}

export default page;
Binary file addedpublic/images/company_placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions utils/flags.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { posthog } from "posthog-js";

export const FEATURE_FLAGS = {
FEATURE_FLAG_TEST: "feature-flag-test",
JOBS: "jobs",
// Add more feature flags as needed
} as const;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
267 changes: 267 additions & 0 deletions app/(app)/jobs/create/_client.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
"use client";

import { Button } from "@/components/ui-components/button";
import {
Checkbox,
CheckboxField,
CheckboxGroup,
} from "@/components/ui-components/checkbox";
import { Divider } from "@/components/ui-components/divider";
import { Description, Field, Label } from "@/components/ui-components/fieldset";
import { Heading, Subheading } from "@/components/ui-components/heading";
import { Input } from "@/components/ui-components/input";
import {
Radio,
RadioField,
RadioGroup,
} from "@/components/ui-components/radio";
import { Strong, Text } from "@/components/ui-components/text";
import { Textarea } from "@/components/ui-components/textarea";
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
import Image from "next/image";
import { notFound } from "next/navigation";
import React, { useRef, useState } from "react";

export default function Content() {
const flagEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
const fileInputRef = useRef<HTMLInputElement>(null);
const [imgUrl, setImgUrl] = useState<string | null>(null);

if (!flagEnabled) {
notFound();
}

return (
<form className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
<Heading level={1}>Post a job</Heading>
<Divider className="my-10 mt-6" />
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Logo</Subheading>
<Text>Square format is best</Text>
</div>
<Field>
<div className="flex items-center space-x-4">
<Image

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin A placeholder will be shown if no url is present

src={imgUrl || "/images/company_placeholder.png"}
width={80}
height={80}
alt="Company Logo"
className="rounded-[10px]"
/>
<div>
<Button
color="dark/white"
className="mt-3 rounded-md"
onClick={() => {
fileInputRef.current?.click();
}}
>
Change Logo
</Button>
<Input
type="file"
id="file-input"
name="company-logo"
accept="image/png, image/gif, image/jpeg"
onChange={() => {}}
className="hidden"
ref={fileInputRef}
/>
<Text className="mt-1 text-xs text-gray-500">
JPG, GIF or PNG. 1MB max.
</Text>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a grey square as a placeholder for the image which will be uploaded.
Otherwise there will be layout shift when an image is added.

We need to be able to see the preview of the image to be uploaded. This preview only needs to be in state. Have a look at the settings page for an example of how this is handled.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin Sure will do that way

</div>
</div>
</Field>
</section>
Comment on lines +34 to +77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement file upload functionality and validation.

The structure for the company logo upload is good, but there are a few improvements needed:

  1. The onChange handler for the file input is empty. Implement logic to handle file selection and update the image preview.
  2. Add validation for file type (JPG, GIF, PNG) and size (1MB max) as mentioned in the UI text.
  3. Update the image preview when a new file is selected.

Here's a suggested implementation:

consthandleFileChange=(event: React.ChangeEvent<HTMLInputElement>)=>{constfile=event.target.files?.[0];if(file){if(file.size>1024*1024){alert('File size should not exceed 1MB');return;}if(!['image/jpeg','image/gif','image/png'].includes(file.type)){alert('Only JPG, GIF, or PNG files are allowed');return;}constreader=newFileReader();reader.onload=(e)=>setImgUrl(e.target?.resultasstring);reader.readAsDataURL(file);}};// Update the Input component:<Inputtype="file"id="file-input"name="company-logo"accept="image/png, image/gif, image/jpeg"onChange={handleFileChange}className="hidden"ref={fileInputRef}/>


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Name</Subheading>
<Text>This will be shown in the format you type it</Text>
</div>
<Field>
<Input
id="company-name"
type="text"
placeholder="Pixel Pulse Studios"
autoComplete="given-company-name"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +95

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for company name.

The structure for the company name section is good, but consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register,formState: { errors }}=useForm();// Update the Input component:<Inputid="company-name"type="text"placeholder="Pixel Pulse Studios"autoComplete="given-company-name"{...register("companyName",{required: "Company name is required"})}/>{errors.companyName&&<span>{errors.companyName.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Title</Subheading>
<Text>The job title for the position that you are opening</Text>
</div>
<Field>
<Input
id="job-title"
type="text"
placeholder="Reality Architect"
autoComplete="given-job-title"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +113

@coderabbitaicoderabbitaiBotOct 12, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation.

The structure for company name and job title sections is consistent and well-organized. However, consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register, handleSubmit,formState: { errors }}=useForm();// In the JSX:<Input{...register("companyName",{required: "Company name is required"})}placeholder="Pixel Pulse Studios"/>{errors.companyName&&<span>{errors.companyName.message}</span>}<Input{...register("jobTitle",{required: "Job title is required"})}placeholder="Reality Architect"/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nil2000 I just noticed that we have no validation on the inputs. Would you add this to the list or would you rather if we merged this and you can do it as a next PR so it doesn't get stale.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NiallJoeMaher Considering Hacktoberfest It would be good for me to have a next PR and you can directly assign that to me 😅

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also love to progress with the other follow up issues mentioned in this issue

Comment on lines +97 to +113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for job title.

Similar to the company name section, implement form state management and validation for the job title. Using the same approach with react-hook-form:

// Update the Input component:<Inputid="job-title"type="text"placeholder="Reality Architect"autoComplete="given-job-title"{...register("jobTitle",{required: "Job title is required"})}/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide consistent form handling across the form fields.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Description</Subheading>
<Text>In markdown format</Text>
</div>
<Field>
<Textarea
id="job-description"
placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."
resizable={false}
rows={3}
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance job description input and implement validation.

  1. Implement form state management and validation for the job description, similar to previous sections.
  2. Consider making the textarea resizable or adjustable to accommodate longer job descriptions.

Here's an example implementation:

<Textareaid="job-description"placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."resizable={true}rows={3}{...register("jobDescription",{required: "Job description is required",minLength: {value: 50,message: "Job description should be at least 50 characters long"}})}/>{errors.jobDescription&&<span>{errors.jobDescription.message}</span>}

This allows for resizable input and adds minimum length validation.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Locations</Subheading>
<Text>
Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”).
</Text>
</div>
<Field>
<Input placeholder="Dublin (2 days in the office per week)" />
<CheckboxGroup className="mt-3">
<CheckboxField>
<Checkbox name="remote" value="is_remote" />
<Label>Work is remote</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="relocation" value="is_relocation_package" />
<Label>Relocation package given</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="visa" value="is_visa_sponsored" />
<Label>Visa sponsorship provided</Label>
</CheckboxField>
</CheckboxGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

The job description section looks good, but the locations section could be improved:

  1. Implement state management for the checkboxes.
  2. Consider allowing multiple location inputs or using a more structured approach for location data.
  3. Add validation for the location input.

Here's an example of how you could improve this section:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index,value)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex-1"><divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div></div>

This implementation allows for multiple locations and manages the state of the checkboxes.

Comment on lines +133 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

Consider the following improvements:

  1. Implement state management for the location input and checkboxes.
  2. Allow for multiple location inputs.
  3. Add validation for the location input.

Here's an example implementation:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index: number,value: string)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div>

This implementation allows for multiple locations and manages the state of the checkboxes.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Application form URL</Subheading>
<Text>A link to your website (optional)</Text>
</div>
<Field>
<Input
id="app-url"
type="text"
autoComplete="url"
placeholder="https://example.com"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and state management for application form URL.

Add URL validation and state management for the application form URL input. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');constvalidateUrl=(url: string)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// Update the Input component:<Inputid="app-url"type="text"autoComplete="url"placeholder="https://example.com"value={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){// Handle invalid URL (e.g., show an error message)}}}/>

This implementation includes URL validation and manages the state of the application URL input.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Type</Subheading>
<Text>Full-time, part-time or freelancer</Text>
</div>
<Field>
<RadioGroup defaultValue="full_time">
<RadioField>
<Radio value="full_time" />
<Label>Full-time (€150)</Label>
<Description>Salaried Position</Description>
</RadioField>
<RadioField>
<Radio value="part_time" />
<Label>Part-time (€100)</Label>
<Description>
Salaried position but less than 4 days per week
</Description>
</RadioField>
<RadioField>
<Radio value="freelancer" />
<Label>Freelancer (€100)</Label>
<Description>Shorter-term usually or fixed term/job</Description>
</RadioField>
<RadioField>
<Radio value="other_role_type" />
<Label>Other (€100)</Label>
<Description>
Looking for a co-founder or something else we haven’t thought of
</Description>
</RadioField>
</RadioGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and radio button state management.

The structure of these sections is good, but consider the following improvements:

  1. Add URL validation for the application form URL input.
  2. Implement state management for the job type radio buttons.

Here's an example of how you could improve these sections:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');const[jobType,setJobType]=useState('full_time');constvalidateUrl=(url)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// In the JSX:<Inputvalue={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){alert('Please enter a valid URL');}}}/><RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation includes URL validation and manages the state of the job type selection.

Comment on lines +180 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement state management for job type selection.

Add state management for the job type radio buttons. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[jobType,setJobType]=useState('full_time');// Update the RadioGroup component:<RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation manages the state of the job type selection, allowing you to easily access the selected job type when submitting the form.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Terms & Conditions</Subheading>
<Text>Ah yes, the fine print.</Text>
</div>
<div className="space-y-2">
<Text>
By submitting this job listing, I acknowledge and agree to the
following terms:
</Text>
<Text>
<Strong>Content Restrictions:</Strong> My listing must not contain:{" "}
<br />- Adult or explicit content <br />- Fraudulent or illegitimate
work opportunities <br />- Inappropriate or offensive language
</Text>
<Text>
<Strong>Accurate Classification: </Strong>I confirm that the job
type (e.g., full-time, part-time, freelance) is correctly
categorized.
</Text>
<Text>
<Strong>Removal Policy:</Strong> I understand that my listing may be
removed without notice if it violates any of the above conditions.
</Text>
<Text>
<Strong>Refund Policy:</Strong> If my listing is removed due to a
violation within 7 days of posting, I may be eligible for a refund,
subject to review.
</Text>
<Text>
<Strong>Compliance:</Strong> I agree to comply with all applicable
laws and regulations regarding job postings and employment
practices.
</Text>
</div>
{/* Add error part after validation here */}
</section>
Comment on lines +218 to +256

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add a checkbox for terms and conditions acceptance.

To ensure users explicitly agree to the terms and conditions, add a checkbox at the end of this section. Here's an example implementation:

import{useState}from'react';// Inside the component:const[termsAccepted,setTermsAccepted]=useState(false);// After the terms and conditions text, add:<CheckboxField><Checkboxname="terms"checked={termsAccepted}onChange={(e)=>setTermsAccepted(e.target.checked)}/><Label>Ihavereadandagreetothetermsandconditions</Label></CheckboxField>

Then, in your form submission logic, you can check if termsAccepted is true before allowing the form to be submitted.


<Divider className="my-10" soft />

<div className="flex justify-end">
<Button className="rounded-md" color="pink">
Submit and checkout
</Button>
</div>
</form>
);
Comment on lines +258 to +266

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement form submission and checkout logic.

The submit button is correctly implemented, but there's no form submission or checkout logic. Consider the following improvements:

  1. Implement form validation before submission.
  2. Add error handling for the submission process.
  3. Integrate with a payment gateway for the checkout process.

Here's a basic example of how you could start implementing this:

import{useState}from'react';// Inside the component:const[isSubmitting,setIsSubmitting]=useState(false);consthandleSubmit=async(event: React.FormEvent)=>{event.preventDefault();setIsSubmitting(true);// Perform form validation heretry{// Submit form data to your APIconstresponse=awaitfetch('/api/job-postings',{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(formData),});if(!response.ok)thrownewError('Submission failed');// If submission is successful, proceed to checkout// Integrate with your payment gateway here// For example, redirect to a Stripe checkout pagewindow.location.href='/checkout';}catch(error){console.error('Error:',error);alert('An error occurred. Please try again.');}finally{setIsSubmitting(false);}};// Update the Button component:<ButtonclassName="rounded-md"color="pink"onClick={handleSubmit}disabled={isSubmitting}>{isSubmitting ? 'Submitting...' : 'Submit and checkout'}</Button>

This implementation includes basic form submission logic and error handling. You'll need to replace the placeholder API call and checkout process with your actual implementation.

}
7 changes: 7 additions & 0 deletions app/(app)/jobs/create/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
import Content from "./_client";

function page() {
return <Content />;
}

export default page;
Binary file addedpublic/images/company_placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions utils/flags.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { posthog } from "posthog-js";

export const FEATURE_FLAGS = {
FEATURE_FLAG_TEST: "feature-flag-test",
JOBS: "jobs",
// Add more feature flags as needed
} as const;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
267 changes: 267 additions & 0 deletions app/(app)/jobs/create/_client.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
"use client";

import { Button } from "@/components/ui-components/button";
import {
Checkbox,
CheckboxField,
CheckboxGroup,
} from "@/components/ui-components/checkbox";
import { Divider } from "@/components/ui-components/divider";
import { Description, Field, Label } from "@/components/ui-components/fieldset";
import { Heading, Subheading } from "@/components/ui-components/heading";
import { Input } from "@/components/ui-components/input";
import {
Radio,
RadioField,
RadioGroup,
} from "@/components/ui-components/radio";
import { Strong, Text } from "@/components/ui-components/text";
import { Textarea } from "@/components/ui-components/textarea";
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
import Image from "next/image";
import { notFound } from "next/navigation";
import React, { useRef, useState } from "react";

export default function Content() {
const flagEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
const fileInputRef = useRef<HTMLInputElement>(null);
const [imgUrl, setImgUrl] = useState<string | null>(null);

if (!flagEnabled) {
notFound();
}

return (
<form className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
<Heading level={1}>Post a job</Heading>
<Divider className="my-10 mt-6" />
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Logo</Subheading>
<Text>Square format is best</Text>
</div>
<Field>
<div className="flex items-center space-x-4">
<Image

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin A placeholder will be shown if no url is present

src={imgUrl || "/images/company_placeholder.png"}
width={80}
height={80}
alt="Company Logo"
className="rounded-[10px]"
/>
<div>
<Button
color="dark/white"
className="mt-3 rounded-md"
onClick={() => {
fileInputRef.current?.click();
}}
>
Change Logo
</Button>
<Input
type="file"
id="file-input"
name="company-logo"
accept="image/png, image/gif, image/jpeg"
onChange={() => {}}
className="hidden"
ref={fileInputRef}
/>
<Text className="mt-1 text-xs text-gray-500">
JPG, GIF or PNG. 1MB max.
</Text>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a grey square as a placeholder for the image which will be uploaded.
Otherwise there will be layout shift when an image is added.

We need to be able to see the preview of the image to be uploaded. This preview only needs to be in state. Have a look at the settings page for an example of how this is handled.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin Sure will do that way

</div>
</div>
</Field>
</section>
Comment on lines +34 to +77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement file upload functionality and validation.

The structure for the company logo upload is good, but there are a few improvements needed:

  1. The onChange handler for the file input is empty. Implement logic to handle file selection and update the image preview.
  2. Add validation for file type (JPG, GIF, PNG) and size (1MB max) as mentioned in the UI text.
  3. Update the image preview when a new file is selected.

Here's a suggested implementation:

consthandleFileChange=(event: React.ChangeEvent<HTMLInputElement>)=>{constfile=event.target.files?.[0];if(file){if(file.size>1024*1024){alert('File size should not exceed 1MB');return;}if(!['image/jpeg','image/gif','image/png'].includes(file.type)){alert('Only JPG, GIF, or PNG files are allowed');return;}constreader=newFileReader();reader.onload=(e)=>setImgUrl(e.target?.resultasstring);reader.readAsDataURL(file);}};// Update the Input component:<Inputtype="file"id="file-input"name="company-logo"accept="image/png, image/gif, image/jpeg"onChange={handleFileChange}className="hidden"ref={fileInputRef}/>


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Name</Subheading>
<Text>This will be shown in the format you type it</Text>
</div>
<Field>
<Input
id="company-name"
type="text"
placeholder="Pixel Pulse Studios"
autoComplete="given-company-name"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +95

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for company name.

The structure for the company name section is good, but consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register,formState: { errors }}=useForm();// Update the Input component:<Inputid="company-name"type="text"placeholder="Pixel Pulse Studios"autoComplete="given-company-name"{...register("companyName",{required: "Company name is required"})}/>{errors.companyName&&<span>{errors.companyName.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Title</Subheading>
<Text>The job title for the position that you are opening</Text>
</div>
<Field>
<Input
id="job-title"
type="text"
placeholder="Reality Architect"
autoComplete="given-job-title"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +113

@coderabbitaicoderabbitaiBotOct 12, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation.

The structure for company name and job title sections is consistent and well-organized. However, consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register, handleSubmit,formState: { errors }}=useForm();// In the JSX:<Input{...register("companyName",{required: "Company name is required"})}placeholder="Pixel Pulse Studios"/>{errors.companyName&&<span>{errors.companyName.message}</span>}<Input{...register("jobTitle",{required: "Job title is required"})}placeholder="Reality Architect"/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nil2000 I just noticed that we have no validation on the inputs. Would you add this to the list or would you rather if we merged this and you can do it as a next PR so it doesn't get stale.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NiallJoeMaher Considering Hacktoberfest It would be good for me to have a next PR and you can directly assign that to me 😅

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also love to progress with the other follow up issues mentioned in this issue

Comment on lines +97 to +113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for job title.

Similar to the company name section, implement form state management and validation for the job title. Using the same approach with react-hook-form:

// Update the Input component:<Inputid="job-title"type="text"placeholder="Reality Architect"autoComplete="given-job-title"{...register("jobTitle",{required: "Job title is required"})}/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide consistent form handling across the form fields.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Description</Subheading>
<Text>In markdown format</Text>
</div>
<Field>
<Textarea
id="job-description"
placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."
resizable={false}
rows={3}
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance job description input and implement validation.

  1. Implement form state management and validation for the job description, similar to previous sections.
  2. Consider making the textarea resizable or adjustable to accommodate longer job descriptions.

Here's an example implementation:

<Textareaid="job-description"placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."resizable={true}rows={3}{...register("jobDescription",{required: "Job description is required",minLength: {value: 50,message: "Job description should be at least 50 characters long"}})}/>{errors.jobDescription&&<span>{errors.jobDescription.message}</span>}

This allows for resizable input and adds minimum length validation.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Locations</Subheading>
<Text>
Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”).
</Text>
</div>
<Field>
<Input placeholder="Dublin (2 days in the office per week)" />
<CheckboxGroup className="mt-3">
<CheckboxField>
<Checkbox name="remote" value="is_remote" />
<Label>Work is remote</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="relocation" value="is_relocation_package" />
<Label>Relocation package given</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="visa" value="is_visa_sponsored" />
<Label>Visa sponsorship provided</Label>
</CheckboxField>
</CheckboxGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

The job description section looks good, but the locations section could be improved:

  1. Implement state management for the checkboxes.
  2. Consider allowing multiple location inputs or using a more structured approach for location data.
  3. Add validation for the location input.

Here's an example of how you could improve this section:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index,value)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex-1"><divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div></div>

This implementation allows for multiple locations and manages the state of the checkboxes.

Comment on lines +133 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

Consider the following improvements:

  1. Implement state management for the location input and checkboxes.
  2. Allow for multiple location inputs.
  3. Add validation for the location input.

Here's an example implementation:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index: number,value: string)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div>

This implementation allows for multiple locations and manages the state of the checkboxes.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Application form URL</Subheading>
<Text>A link to your website (optional)</Text>
</div>
<Field>
<Input
id="app-url"
type="text"
autoComplete="url"
placeholder="https://example.com"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and state management for application form URL.

Add URL validation and state management for the application form URL input. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');constvalidateUrl=(url: string)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// Update the Input component:<Inputid="app-url"type="text"autoComplete="url"placeholder="https://example.com"value={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){// Handle invalid URL (e.g., show an error message)}}}/>

This implementation includes URL validation and manages the state of the application URL input.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Type</Subheading>
<Text>Full-time, part-time or freelancer</Text>
</div>
<Field>
<RadioGroup defaultValue="full_time">
<RadioField>
<Radio value="full_time" />
<Label>Full-time (€150)</Label>
<Description>Salaried Position</Description>
</RadioField>
<RadioField>
<Radio value="part_time" />
<Label>Part-time (€100)</Label>
<Description>
Salaried position but less than 4 days per week
</Description>
</RadioField>
<RadioField>
<Radio value="freelancer" />
<Label>Freelancer (€100)</Label>
<Description>Shorter-term usually or fixed term/job</Description>
</RadioField>
<RadioField>
<Radio value="other_role_type" />
<Label>Other (€100)</Label>
<Description>
Looking for a co-founder or something else we haven’t thought of
</Description>
</RadioField>
</RadioGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and radio button state management.

The structure of these sections is good, but consider the following improvements:

  1. Add URL validation for the application form URL input.
  2. Implement state management for the job type radio buttons.

Here's an example of how you could improve these sections:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');const[jobType,setJobType]=useState('full_time');constvalidateUrl=(url)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// In the JSX:<Inputvalue={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){alert('Please enter a valid URL');}}}/><RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation includes URL validation and manages the state of the job type selection.

Comment on lines +180 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement state management for job type selection.

Add state management for the job type radio buttons. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[jobType,setJobType]=useState('full_time');// Update the RadioGroup component:<RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation manages the state of the job type selection, allowing you to easily access the selected job type when submitting the form.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Terms & Conditions</Subheading>
<Text>Ah yes, the fine print.</Text>
</div>
<div className="space-y-2">
<Text>
By submitting this job listing, I acknowledge and agree to the
following terms:
</Text>
<Text>
<Strong>Content Restrictions:</Strong> My listing must not contain:{" "}
<br />- Adult or explicit content <br />- Fraudulent or illegitimate
work opportunities <br />- Inappropriate or offensive language
</Text>
<Text>
<Strong>Accurate Classification: </Strong>I confirm that the job
type (e.g., full-time, part-time, freelance) is correctly
categorized.
</Text>
<Text>
<Strong>Removal Policy:</Strong> I understand that my listing may be
removed without notice if it violates any of the above conditions.
</Text>
<Text>
<Strong>Refund Policy:</Strong> If my listing is removed due to a
violation within 7 days of posting, I may be eligible for a refund,
subject to review.
</Text>
<Text>
<Strong>Compliance:</Strong> I agree to comply with all applicable
laws and regulations regarding job postings and employment
practices.
</Text>
</div>
{/* Add error part after validation here */}
</section>
Comment on lines +218 to +256

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add a checkbox for terms and conditions acceptance.

To ensure users explicitly agree to the terms and conditions, add a checkbox at the end of this section. Here's an example implementation:

import{useState}from'react';// Inside the component:const[termsAccepted,setTermsAccepted]=useState(false);// After the terms and conditions text, add:<CheckboxField><Checkboxname="terms"checked={termsAccepted}onChange={(e)=>setTermsAccepted(e.target.checked)}/><Label>Ihavereadandagreetothetermsandconditions</Label></CheckboxField>

Then, in your form submission logic, you can check if termsAccepted is true before allowing the form to be submitted.


<Divider className="my-10" soft />

<div className="flex justify-end">
<Button className="rounded-md" color="pink">
Submit and checkout
</Button>
</div>
</form>
);
Comment on lines +258 to +266

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement form submission and checkout logic.

The submit button is correctly implemented, but there's no form submission or checkout logic. Consider the following improvements:

  1. Implement form validation before submission.
  2. Add error handling for the submission process.
  3. Integrate with a payment gateway for the checkout process.

Here's a basic example of how you could start implementing this:

import{useState}from'react';// Inside the component:const[isSubmitting,setIsSubmitting]=useState(false);consthandleSubmit=async(event: React.FormEvent)=>{event.preventDefault();setIsSubmitting(true);// Perform form validation heretry{// Submit form data to your APIconstresponse=awaitfetch('/api/job-postings',{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(formData),});if(!response.ok)thrownewError('Submission failed');// If submission is successful, proceed to checkout// Integrate with your payment gateway here// For example, redirect to a Stripe checkout pagewindow.location.href='/checkout';}catch(error){console.error('Error:',error);alert('An error occurred. Please try again.');}finally{setIsSubmitting(false);}};// Update the Button component:<ButtonclassName="rounded-md"color="pink"onClick={handleSubmit}disabled={isSubmitting}>{isSubmitting ? 'Submitting...' : 'Submit and checkout'}</Button>

This implementation includes basic form submission logic and error handling. You'll need to replace the placeholder API call and checkout process with your actual implementation.

}
7 changes: 7 additions & 0 deletions app/(app)/jobs/create/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
import Content from "./_client";

function page() {
return <Content />;
}

export default page;
Binary file addedpublic/images/company_placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions utils/flags.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { posthog } from "posthog-js";

export const FEATURE_FLAGS = {
FEATURE_FLAG_TEST: "feature-flag-test",
JOBS: "jobs",
// Add more feature flags as needed
} as const;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
267 changes: 267 additions & 0 deletions app/(app)/jobs/create/_client.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
"use client";

import { Button } from "@/components/ui-components/button";
import {
Checkbox,
CheckboxField,
CheckboxGroup,
} from "@/components/ui-components/checkbox";
import { Divider } from "@/components/ui-components/divider";
import { Description, Field, Label } from "@/components/ui-components/fieldset";
import { Heading, Subheading } from "@/components/ui-components/heading";
import { Input } from "@/components/ui-components/input";
import {
Radio,
RadioField,
RadioGroup,
} from "@/components/ui-components/radio";
import { Strong, Text } from "@/components/ui-components/text";
import { Textarea } from "@/components/ui-components/textarea";
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
import Image from "next/image";
import { notFound } from "next/navigation";
import React, { useRef, useState } from "react";

export default function Content() {
const flagEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
const fileInputRef = useRef<HTMLInputElement>(null);
const [imgUrl, setImgUrl] = useState<string | null>(null);

if (!flagEnabled) {
notFound();
}

return (
<form className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
<Heading level={1}>Post a job</Heading>
<Divider className="my-10 mt-6" />
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Logo</Subheading>
<Text>Square format is best</Text>
</div>
<Field>
<div className="flex items-center space-x-4">
<Image

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin A placeholder will be shown if no url is present

src={imgUrl || "/images/company_placeholder.png"}
width={80}
height={80}
alt="Company Logo"
className="rounded-[10px]"
/>
<div>
<Button
color="dark/white"
className="mt-3 rounded-md"
onClick={() => {
fileInputRef.current?.click();
}}
>
Change Logo
</Button>
<Input
type="file"
id="file-input"
name="company-logo"
accept="image/png, image/gif, image/jpeg"
onChange={() => {}}
className="hidden"
ref={fileInputRef}
/>
<Text className="mt-1 text-xs text-gray-500">
JPG, GIF or PNG. 1MB max.
</Text>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a grey square as a placeholder for the image which will be uploaded.
Otherwise there will be layout shift when an image is added.

We need to be able to see the preview of the image to be uploaded. This preview only needs to be in state. Have a look at the settings page for an example of how this is handled.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin Sure will do that way

</div>
</div>
</Field>
</section>
Comment on lines +34 to +77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement file upload functionality and validation.

The structure for the company logo upload is good, but there are a few improvements needed:

  1. The onChange handler for the file input is empty. Implement logic to handle file selection and update the image preview.
  2. Add validation for file type (JPG, GIF, PNG) and size (1MB max) as mentioned in the UI text.
  3. Update the image preview when a new file is selected.

Here's a suggested implementation:

consthandleFileChange=(event: React.ChangeEvent<HTMLInputElement>)=>{constfile=event.target.files?.[0];if(file){if(file.size>1024*1024){alert('File size should not exceed 1MB');return;}if(!['image/jpeg','image/gif','image/png'].includes(file.type)){alert('Only JPG, GIF, or PNG files are allowed');return;}constreader=newFileReader();reader.onload=(e)=>setImgUrl(e.target?.resultasstring);reader.readAsDataURL(file);}};// Update the Input component:<Inputtype="file"id="file-input"name="company-logo"accept="image/png, image/gif, image/jpeg"onChange={handleFileChange}className="hidden"ref={fileInputRef}/>


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Name</Subheading>
<Text>This will be shown in the format you type it</Text>
</div>
<Field>
<Input
id="company-name"
type="text"
placeholder="Pixel Pulse Studios"
autoComplete="given-company-name"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +95

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for company name.

The structure for the company name section is good, but consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register,formState: { errors }}=useForm();// Update the Input component:<Inputid="company-name"type="text"placeholder="Pixel Pulse Studios"autoComplete="given-company-name"{...register("companyName",{required: "Company name is required"})}/>{errors.companyName&&<span>{errors.companyName.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Title</Subheading>
<Text>The job title for the position that you are opening</Text>
</div>
<Field>
<Input
id="job-title"
type="text"
placeholder="Reality Architect"
autoComplete="given-job-title"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +113

@coderabbitaicoderabbitaiBotOct 12, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation.

The structure for company name and job title sections is consistent and well-organized. However, consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register, handleSubmit,formState: { errors }}=useForm();// In the JSX:<Input{...register("companyName",{required: "Company name is required"})}placeholder="Pixel Pulse Studios"/>{errors.companyName&&<span>{errors.companyName.message}</span>}<Input{...register("jobTitle",{required: "Job title is required"})}placeholder="Reality Architect"/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nil2000 I just noticed that we have no validation on the inputs. Would you add this to the list or would you rather if we merged this and you can do it as a next PR so it doesn't get stale.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NiallJoeMaher Considering Hacktoberfest It would be good for me to have a next PR and you can directly assign that to me 😅

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also love to progress with the other follow up issues mentioned in this issue

Comment on lines +97 to +113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for job title.

Similar to the company name section, implement form state management and validation for the job title. Using the same approach with react-hook-form:

// Update the Input component:<Inputid="job-title"type="text"placeholder="Reality Architect"autoComplete="given-job-title"{...register("jobTitle",{required: "Job title is required"})}/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide consistent form handling across the form fields.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Description</Subheading>
<Text>In markdown format</Text>
</div>
<Field>
<Textarea
id="job-description"
placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."
resizable={false}
rows={3}
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance job description input and implement validation.

  1. Implement form state management and validation for the job description, similar to previous sections.
  2. Consider making the textarea resizable or adjustable to accommodate longer job descriptions.

Here's an example implementation:

<Textareaid="job-description"placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."resizable={true}rows={3}{...register("jobDescription",{required: "Job description is required",minLength: {value: 50,message: "Job description should be at least 50 characters long"}})}/>{errors.jobDescription&&<span>{errors.jobDescription.message}</span>}

This allows for resizable input and adds minimum length validation.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Locations</Subheading>
<Text>
Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”).
</Text>
</div>
<Field>
<Input placeholder="Dublin (2 days in the office per week)" />
<CheckboxGroup className="mt-3">
<CheckboxField>
<Checkbox name="remote" value="is_remote" />
<Label>Work is remote</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="relocation" value="is_relocation_package" />
<Label>Relocation package given</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="visa" value="is_visa_sponsored" />
<Label>Visa sponsorship provided</Label>
</CheckboxField>
</CheckboxGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

The job description section looks good, but the locations section could be improved:

  1. Implement state management for the checkboxes.
  2. Consider allowing multiple location inputs or using a more structured approach for location data.
  3. Add validation for the location input.

Here's an example of how you could improve this section:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index,value)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex-1"><divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div></div>

This implementation allows for multiple locations and manages the state of the checkboxes.

Comment on lines +133 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

Consider the following improvements:

  1. Implement state management for the location input and checkboxes.
  2. Allow for multiple location inputs.
  3. Add validation for the location input.

Here's an example implementation:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index: number,value: string)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div>

This implementation allows for multiple locations and manages the state of the checkboxes.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Application form URL</Subheading>
<Text>A link to your website (optional)</Text>
</div>
<Field>
<Input
id="app-url"
type="text"
autoComplete="url"
placeholder="https://example.com"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and state management for application form URL.

Add URL validation and state management for the application form URL input. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');constvalidateUrl=(url: string)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// Update the Input component:<Inputid="app-url"type="text"autoComplete="url"placeholder="https://example.com"value={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){// Handle invalid URL (e.g., show an error message)}}}/>

This implementation includes URL validation and manages the state of the application URL input.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Type</Subheading>
<Text>Full-time, part-time or freelancer</Text>
</div>
<Field>
<RadioGroup defaultValue="full_time">
<RadioField>
<Radio value="full_time" />
<Label>Full-time (€150)</Label>
<Description>Salaried Position</Description>
</RadioField>
<RadioField>
<Radio value="part_time" />
<Label>Part-time (€100)</Label>
<Description>
Salaried position but less than 4 days per week
</Description>
</RadioField>
<RadioField>
<Radio value="freelancer" />
<Label>Freelancer (€100)</Label>
<Description>Shorter-term usually or fixed term/job</Description>
</RadioField>
<RadioField>
<Radio value="other_role_type" />
<Label>Other (€100)</Label>
<Description>
Looking for a co-founder or something else we haven’t thought of
</Description>
</RadioField>
</RadioGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and radio button state management.

The structure of these sections is good, but consider the following improvements:

  1. Add URL validation for the application form URL input.
  2. Implement state management for the job type radio buttons.

Here's an example of how you could improve these sections:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');const[jobType,setJobType]=useState('full_time');constvalidateUrl=(url)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// In the JSX:<Inputvalue={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){alert('Please enter a valid URL');}}}/><RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation includes URL validation and manages the state of the job type selection.

Comment on lines +180 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement state management for job type selection.

Add state management for the job type radio buttons. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[jobType,setJobType]=useState('full_time');// Update the RadioGroup component:<RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation manages the state of the job type selection, allowing you to easily access the selected job type when submitting the form.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Terms & Conditions</Subheading>
<Text>Ah yes, the fine print.</Text>
</div>
<div className="space-y-2">
<Text>
By submitting this job listing, I acknowledge and agree to the
following terms:
</Text>
<Text>
<Strong>Content Restrictions:</Strong> My listing must not contain:{" "}
<br />- Adult or explicit content <br />- Fraudulent or illegitimate
work opportunities <br />- Inappropriate or offensive language
</Text>
<Text>
<Strong>Accurate Classification: </Strong>I confirm that the job
type (e.g., full-time, part-time, freelance) is correctly
categorized.
</Text>
<Text>
<Strong>Removal Policy:</Strong> I understand that my listing may be
removed without notice if it violates any of the above conditions.
</Text>
<Text>
<Strong>Refund Policy:</Strong> If my listing is removed due to a
violation within 7 days of posting, I may be eligible for a refund,
subject to review.
</Text>
<Text>
<Strong>Compliance:</Strong> I agree to comply with all applicable
laws and regulations regarding job postings and employment
practices.
</Text>
</div>
{/* Add error part after validation here */}
</section>
Comment on lines +218 to +256

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add a checkbox for terms and conditions acceptance.

To ensure users explicitly agree to the terms and conditions, add a checkbox at the end of this section. Here's an example implementation:

import{useState}from'react';// Inside the component:const[termsAccepted,setTermsAccepted]=useState(false);// After the terms and conditions text, add:<CheckboxField><Checkboxname="terms"checked={termsAccepted}onChange={(e)=>setTermsAccepted(e.target.checked)}/><Label>Ihavereadandagreetothetermsandconditions</Label></CheckboxField>

Then, in your form submission logic, you can check if termsAccepted is true before allowing the form to be submitted.


<Divider className="my-10" soft />

<div className="flex justify-end">
<Button className="rounded-md" color="pink">
Submit and checkout
</Button>
</div>
</form>
);
Comment on lines +258 to +266

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement form submission and checkout logic.

The submit button is correctly implemented, but there's no form submission or checkout logic. Consider the following improvements:

  1. Implement form validation before submission.
  2. Add error handling for the submission process.
  3. Integrate with a payment gateway for the checkout process.

Here's a basic example of how you could start implementing this:

import{useState}from'react';// Inside the component:const[isSubmitting,setIsSubmitting]=useState(false);consthandleSubmit=async(event: React.FormEvent)=>{event.preventDefault();setIsSubmitting(true);// Perform form validation heretry{// Submit form data to your APIconstresponse=awaitfetch('/api/job-postings',{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(formData),});if(!response.ok)thrownewError('Submission failed');// If submission is successful, proceed to checkout// Integrate with your payment gateway here// For example, redirect to a Stripe checkout pagewindow.location.href='/checkout';}catch(error){console.error('Error:',error);alert('An error occurred. Please try again.');}finally{setIsSubmitting(false);}};// Update the Button component:<ButtonclassName="rounded-md"color="pink"onClick={handleSubmit}disabled={isSubmitting}>{isSubmitting ? 'Submitting...' : 'Submit and checkout'}</Button>

This implementation includes basic form submission logic and error handling. You'll need to replace the placeholder API call and checkout process with your actual implementation.

}
7 changes: 7 additions & 0 deletions app/(app)/jobs/create/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
import Content from "./_client";

function page() {
return <Content />;
}

export default page;
Binary file addedpublic/images/company_placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions utils/flags.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { posthog } from "posthog-js";

export const FEATURE_FLAGS = {
FEATURE_FLAG_TEST: "feature-flag-test",
JOBS: "jobs",
// Add more feature flags as needed
} as const;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
267 changes: 267 additions & 0 deletions app/(app)/jobs/create/_client.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
"use client";

import { Button } from "@/components/ui-components/button";
import {
Checkbox,
CheckboxField,
CheckboxGroup,
} from "@/components/ui-components/checkbox";
import { Divider } from "@/components/ui-components/divider";
import { Description, Field, Label } from "@/components/ui-components/fieldset";
import { Heading, Subheading } from "@/components/ui-components/heading";
import { Input } from "@/components/ui-components/input";
import {
Radio,
RadioField,
RadioGroup,
} from "@/components/ui-components/radio";
import { Strong, Text } from "@/components/ui-components/text";
import { Textarea } from "@/components/ui-components/textarea";
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
import Image from "next/image";
import { notFound } from "next/navigation";
import React, { useRef, useState } from "react";

export default function Content() {
const flagEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
const fileInputRef = useRef<HTMLInputElement>(null);
const [imgUrl, setImgUrl] = useState<string | null>(null);

if (!flagEnabled) {
notFound();
}

return (
<form className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
<Heading level={1}>Post a job</Heading>
<Divider className="my-10 mt-6" />
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Logo</Subheading>
<Text>Square format is best</Text>
</div>
<Field>
<div className="flex items-center space-x-4">
<Image

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin A placeholder will be shown if no url is present

src={imgUrl || "/images/company_placeholder.png"}
width={80}
height={80}
alt="Company Logo"
className="rounded-[10px]"
/>
<div>
<Button
color="dark/white"
className="mt-3 rounded-md"
onClick={() => {
fileInputRef.current?.click();
}}
>
Change Logo
</Button>
<Input
type="file"
id="file-input"
name="company-logo"
accept="image/png, image/gif, image/jpeg"
onChange={() => {}}
className="hidden"
ref={fileInputRef}
/>
<Text className="mt-1 text-xs text-gray-500">
JPG, GIF or PNG. 1MB max.
</Text>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a grey square as a placeholder for the image which will be uploaded.
Otherwise there will be layout shift when an image is added.

We need to be able to see the preview of the image to be uploaded. This preview only needs to be in state. Have a look at the settings page for an example of how this is handled.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin Sure will do that way

</div>
</div>
</Field>
</section>
Comment on lines +34 to +77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement file upload functionality and validation.

The structure for the company logo upload is good, but there are a few improvements needed:

  1. The onChange handler for the file input is empty. Implement logic to handle file selection and update the image preview.
  2. Add validation for file type (JPG, GIF, PNG) and size (1MB max) as mentioned in the UI text.
  3. Update the image preview when a new file is selected.

Here's a suggested implementation:

consthandleFileChange=(event: React.ChangeEvent<HTMLInputElement>)=>{constfile=event.target.files?.[0];if(file){if(file.size>1024*1024){alert('File size should not exceed 1MB');return;}if(!['image/jpeg','image/gif','image/png'].includes(file.type)){alert('Only JPG, GIF, or PNG files are allowed');return;}constreader=newFileReader();reader.onload=(e)=>setImgUrl(e.target?.resultasstring);reader.readAsDataURL(file);}};// Update the Input component:<Inputtype="file"id="file-input"name="company-logo"accept="image/png, image/gif, image/jpeg"onChange={handleFileChange}className="hidden"ref={fileInputRef}/>


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Name</Subheading>
<Text>This will be shown in the format you type it</Text>
</div>
<Field>
<Input
id="company-name"
type="text"
placeholder="Pixel Pulse Studios"
autoComplete="given-company-name"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +95

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for company name.

The structure for the company name section is good, but consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register,formState: { errors }}=useForm();// Update the Input component:<Inputid="company-name"type="text"placeholder="Pixel Pulse Studios"autoComplete="given-company-name"{...register("companyName",{required: "Company name is required"})}/>{errors.companyName&&<span>{errors.companyName.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Title</Subheading>
<Text>The job title for the position that you are opening</Text>
</div>
<Field>
<Input
id="job-title"
type="text"
placeholder="Reality Architect"
autoComplete="given-job-title"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +113

@coderabbitaicoderabbitaiBotOct 12, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation.

The structure for company name and job title sections is consistent and well-organized. However, consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register, handleSubmit,formState: { errors }}=useForm();// In the JSX:<Input{...register("companyName",{required: "Company name is required"})}placeholder="Pixel Pulse Studios"/>{errors.companyName&&<span>{errors.companyName.message}</span>}<Input{...register("jobTitle",{required: "Job title is required"})}placeholder="Reality Architect"/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nil2000 I just noticed that we have no validation on the inputs. Would you add this to the list or would you rather if we merged this and you can do it as a next PR so it doesn't get stale.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NiallJoeMaher Considering Hacktoberfest It would be good for me to have a next PR and you can directly assign that to me 😅

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also love to progress with the other follow up issues mentioned in this issue

Comment on lines +97 to +113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for job title.

Similar to the company name section, implement form state management and validation for the job title. Using the same approach with react-hook-form:

// Update the Input component:<Inputid="job-title"type="text"placeholder="Reality Architect"autoComplete="given-job-title"{...register("jobTitle",{required: "Job title is required"})}/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide consistent form handling across the form fields.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Description</Subheading>
<Text>In markdown format</Text>
</div>
<Field>
<Textarea
id="job-description"
placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."
resizable={false}
rows={3}
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance job description input and implement validation.

  1. Implement form state management and validation for the job description, similar to previous sections.
  2. Consider making the textarea resizable or adjustable to accommodate longer job descriptions.

Here's an example implementation:

<Textareaid="job-description"placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."resizable={true}rows={3}{...register("jobDescription",{required: "Job description is required",minLength: {value: 50,message: "Job description should be at least 50 characters long"}})}/>{errors.jobDescription&&<span>{errors.jobDescription.message}</span>}

This allows for resizable input and adds minimum length validation.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Locations</Subheading>
<Text>
Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”).
</Text>
</div>
<Field>
<Input placeholder="Dublin (2 days in the office per week)" />
<CheckboxGroup className="mt-3">
<CheckboxField>
<Checkbox name="remote" value="is_remote" />
<Label>Work is remote</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="relocation" value="is_relocation_package" />
<Label>Relocation package given</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="visa" value="is_visa_sponsored" />
<Label>Visa sponsorship provided</Label>
</CheckboxField>
</CheckboxGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

The job description section looks good, but the locations section could be improved:

  1. Implement state management for the checkboxes.
  2. Consider allowing multiple location inputs or using a more structured approach for location data.
  3. Add validation for the location input.

Here's an example of how you could improve this section:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index,value)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex-1"><divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div></div>

This implementation allows for multiple locations and manages the state of the checkboxes.

Comment on lines +133 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

Consider the following improvements:

  1. Implement state management for the location input and checkboxes.
  2. Allow for multiple location inputs.
  3. Add validation for the location input.

Here's an example implementation:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index: number,value: string)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div>

This implementation allows for multiple locations and manages the state of the checkboxes.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Application form URL</Subheading>
<Text>A link to your website (optional)</Text>
</div>
<Field>
<Input
id="app-url"
type="text"
autoComplete="url"
placeholder="https://example.com"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and state management for application form URL.

Add URL validation and state management for the application form URL input. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');constvalidateUrl=(url: string)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// Update the Input component:<Inputid="app-url"type="text"autoComplete="url"placeholder="https://example.com"value={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){// Handle invalid URL (e.g., show an error message)}}}/>

This implementation includes URL validation and manages the state of the application URL input.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Type</Subheading>
<Text>Full-time, part-time or freelancer</Text>
</div>
<Field>
<RadioGroup defaultValue="full_time">
<RadioField>
<Radio value="full_time" />
<Label>Full-time (€150)</Label>
<Description>Salaried Position</Description>
</RadioField>
<RadioField>
<Radio value="part_time" />
<Label>Part-time (€100)</Label>
<Description>
Salaried position but less than 4 days per week
</Description>
</RadioField>
<RadioField>
<Radio value="freelancer" />
<Label>Freelancer (€100)</Label>
<Description>Shorter-term usually or fixed term/job</Description>
</RadioField>
<RadioField>
<Radio value="other_role_type" />
<Label>Other (€100)</Label>
<Description>
Looking for a co-founder or something else we haven’t thought of
</Description>
</RadioField>
</RadioGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and radio button state management.

The structure of these sections is good, but consider the following improvements:

  1. Add URL validation for the application form URL input.
  2. Implement state management for the job type radio buttons.

Here's an example of how you could improve these sections:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');const[jobType,setJobType]=useState('full_time');constvalidateUrl=(url)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// In the JSX:<Inputvalue={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){alert('Please enter a valid URL');}}}/><RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation includes URL validation and manages the state of the job type selection.

Comment on lines +180 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement state management for job type selection.

Add state management for the job type radio buttons. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[jobType,setJobType]=useState('full_time');// Update the RadioGroup component:<RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation manages the state of the job type selection, allowing you to easily access the selected job type when submitting the form.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Terms & Conditions</Subheading>
<Text>Ah yes, the fine print.</Text>
</div>
<div className="space-y-2">
<Text>
By submitting this job listing, I acknowledge and agree to the
following terms:
</Text>
<Text>
<Strong>Content Restrictions:</Strong> My listing must not contain:{" "}
<br />- Adult or explicit content <br />- Fraudulent or illegitimate
work opportunities <br />- Inappropriate or offensive language
</Text>
<Text>
<Strong>Accurate Classification: </Strong>I confirm that the job
type (e.g., full-time, part-time, freelance) is correctly
categorized.
</Text>
<Text>
<Strong>Removal Policy:</Strong> I understand that my listing may be
removed without notice if it violates any of the above conditions.
</Text>
<Text>
<Strong>Refund Policy:</Strong> If my listing is removed due to a
violation within 7 days of posting, I may be eligible for a refund,
subject to review.
</Text>
<Text>
<Strong>Compliance:</Strong> I agree to comply with all applicable
laws and regulations regarding job postings and employment
practices.
</Text>
</div>
{/* Add error part after validation here */}
</section>
Comment on lines +218 to +256

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add a checkbox for terms and conditions acceptance.

To ensure users explicitly agree to the terms and conditions, add a checkbox at the end of this section. Here's an example implementation:

import{useState}from'react';// Inside the component:const[termsAccepted,setTermsAccepted]=useState(false);// After the terms and conditions text, add:<CheckboxField><Checkboxname="terms"checked={termsAccepted}onChange={(e)=>setTermsAccepted(e.target.checked)}/><Label>Ihavereadandagreetothetermsandconditions</Label></CheckboxField>

Then, in your form submission logic, you can check if termsAccepted is true before allowing the form to be submitted.


<Divider className="my-10" soft />

<div className="flex justify-end">
<Button className="rounded-md" color="pink">
Submit and checkout
</Button>
</div>
</form>
);
Comment on lines +258 to +266

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement form submission and checkout logic.

The submit button is correctly implemented, but there's no form submission or checkout logic. Consider the following improvements:

  1. Implement form validation before submission.
  2. Add error handling for the submission process.
  3. Integrate with a payment gateway for the checkout process.

Here's a basic example of how you could start implementing this:

import{useState}from'react';// Inside the component:const[isSubmitting,setIsSubmitting]=useState(false);consthandleSubmit=async(event: React.FormEvent)=>{event.preventDefault();setIsSubmitting(true);// Perform form validation heretry{// Submit form data to your APIconstresponse=awaitfetch('/api/job-postings',{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(formData),});if(!response.ok)thrownewError('Submission failed');// If submission is successful, proceed to checkout// Integrate with your payment gateway here// For example, redirect to a Stripe checkout pagewindow.location.href='/checkout';}catch(error){console.error('Error:',error);alert('An error occurred. Please try again.');}finally{setIsSubmitting(false);}};// Update the Button component:<ButtonclassName="rounded-md"color="pink"onClick={handleSubmit}disabled={isSubmitting}>{isSubmitting ? 'Submitting...' : 'Submit and checkout'}</Button>

This implementation includes basic form submission logic and error handling. You'll need to replace the placeholder API call and checkout process with your actual implementation.

}
7 changes: 7 additions & 0 deletions app/(app)/jobs/create/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
import Content from "./_client";

function page() {
return <Content />;
}

export default page;
Binary file addedpublic/images/company_placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions utils/flags.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { posthog } from "posthog-js";

export const FEATURE_FLAGS = {
FEATURE_FLAG_TEST: "feature-flag-test",
JOBS: "jobs",
// Add more feature flags as needed
} as const;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
267 changes: 267 additions & 0 deletions app/(app)/jobs/create/_client.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
"use client";

import { Button } from "@/components/ui-components/button";
import {
Checkbox,
CheckboxField,
CheckboxGroup,
} from "@/components/ui-components/checkbox";
import { Divider } from "@/components/ui-components/divider";
import { Description, Field, Label } from "@/components/ui-components/fieldset";
import { Heading, Subheading } from "@/components/ui-components/heading";
import { Input } from "@/components/ui-components/input";
import {
Radio,
RadioField,
RadioGroup,
} from "@/components/ui-components/radio";
import { Strong, Text } from "@/components/ui-components/text";
import { Textarea } from "@/components/ui-components/textarea";
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
import Image from "next/image";
import { notFound } from "next/navigation";
import React, { useRef, useState } from "react";

export default function Content() {
const flagEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
const fileInputRef = useRef<HTMLInputElement>(null);
const [imgUrl, setImgUrl] = useState<string | null>(null);

if (!flagEnabled) {
notFound();
}

return (
<form className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
<Heading level={1}>Post a job</Heading>
<Divider className="my-10 mt-6" />
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Logo</Subheading>
<Text>Square format is best</Text>
</div>
<Field>
<div className="flex items-center space-x-4">
<Image

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin A placeholder will be shown if no url is present

src={imgUrl || "/images/company_placeholder.png"}
width={80}
height={80}
alt="Company Logo"
className="rounded-[10px]"
/>
<div>
<Button
color="dark/white"
className="mt-3 rounded-md"
onClick={() => {
fileInputRef.current?.click();
}}
>
Change Logo
</Button>
<Input
type="file"
id="file-input"
name="company-logo"
accept="image/png, image/gif, image/jpeg"
onChange={() => {}}
className="hidden"
ref={fileInputRef}
/>
<Text className="mt-1 text-xs text-gray-500">
JPG, GIF or PNG. 1MB max.
</Text>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a grey square as a placeholder for the image which will be uploaded.
Otherwise there will be layout shift when an image is added.

We need to be able to see the preview of the image to be uploaded. This preview only needs to be in state. Have a look at the settings page for an example of how this is handled.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin Sure will do that way

</div>
</div>
</Field>
</section>
Comment on lines +34 to +77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement file upload functionality and validation.

The structure for the company logo upload is good, but there are a few improvements needed:

  1. The onChange handler for the file input is empty. Implement logic to handle file selection and update the image preview.
  2. Add validation for file type (JPG, GIF, PNG) and size (1MB max) as mentioned in the UI text.
  3. Update the image preview when a new file is selected.

Here's a suggested implementation:

consthandleFileChange=(event: React.ChangeEvent<HTMLInputElement>)=>{constfile=event.target.files?.[0];if(file){if(file.size>1024*1024){alert('File size should not exceed 1MB');return;}if(!['image/jpeg','image/gif','image/png'].includes(file.type)){alert('Only JPG, GIF, or PNG files are allowed');return;}constreader=newFileReader();reader.onload=(e)=>setImgUrl(e.target?.resultasstring);reader.readAsDataURL(file);}};// Update the Input component:<Inputtype="file"id="file-input"name="company-logo"accept="image/png, image/gif, image/jpeg"onChange={handleFileChange}className="hidden"ref={fileInputRef}/>


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Name</Subheading>
<Text>This will be shown in the format you type it</Text>
</div>
<Field>
<Input
id="company-name"
type="text"
placeholder="Pixel Pulse Studios"
autoComplete="given-company-name"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +95

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for company name.

The structure for the company name section is good, but consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register,formState: { errors }}=useForm();// Update the Input component:<Inputid="company-name"type="text"placeholder="Pixel Pulse Studios"autoComplete="given-company-name"{...register("companyName",{required: "Company name is required"})}/>{errors.companyName&&<span>{errors.companyName.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Title</Subheading>
<Text>The job title for the position that you are opening</Text>
</div>
<Field>
<Input
id="job-title"
type="text"
placeholder="Reality Architect"
autoComplete="given-job-title"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +113

@coderabbitaicoderabbitaiBotOct 12, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation.

The structure for company name and job title sections is consistent and well-organized. However, consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register, handleSubmit,formState: { errors }}=useForm();// In the JSX:<Input{...register("companyName",{required: "Company name is required"})}placeholder="Pixel Pulse Studios"/>{errors.companyName&&<span>{errors.companyName.message}</span>}<Input{...register("jobTitle",{required: "Job title is required"})}placeholder="Reality Architect"/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nil2000 I just noticed that we have no validation on the inputs. Would you add this to the list or would you rather if we merged this and you can do it as a next PR so it doesn't get stale.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NiallJoeMaher Considering Hacktoberfest It would be good for me to have a next PR and you can directly assign that to me 😅

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also love to progress with the other follow up issues mentioned in this issue

Comment on lines +97 to +113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for job title.

Similar to the company name section, implement form state management and validation for the job title. Using the same approach with react-hook-form:

// Update the Input component:<Inputid="job-title"type="text"placeholder="Reality Architect"autoComplete="given-job-title"{...register("jobTitle",{required: "Job title is required"})}/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide consistent form handling across the form fields.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Description</Subheading>
<Text>In markdown format</Text>
</div>
<Field>
<Textarea
id="job-description"
placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."
resizable={false}
rows={3}
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance job description input and implement validation.

  1. Implement form state management and validation for the job description, similar to previous sections.
  2. Consider making the textarea resizable or adjustable to accommodate longer job descriptions.

Here's an example implementation:

<Textareaid="job-description"placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."resizable={true}rows={3}{...register("jobDescription",{required: "Job description is required",minLength: {value: 50,message: "Job description should be at least 50 characters long"}})}/>{errors.jobDescription&&<span>{errors.jobDescription.message}</span>}

This allows for resizable input and adds minimum length validation.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Locations</Subheading>
<Text>
Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”).
</Text>
</div>
<Field>
<Input placeholder="Dublin (2 days in the office per week)" />
<CheckboxGroup className="mt-3">
<CheckboxField>
<Checkbox name="remote" value="is_remote" />
<Label>Work is remote</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="relocation" value="is_relocation_package" />
<Label>Relocation package given</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="visa" value="is_visa_sponsored" />
<Label>Visa sponsorship provided</Label>
</CheckboxField>
</CheckboxGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

The job description section looks good, but the locations section could be improved:

  1. Implement state management for the checkboxes.
  2. Consider allowing multiple location inputs or using a more structured approach for location data.
  3. Add validation for the location input.

Here's an example of how you could improve this section:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index,value)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex-1"><divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div></div>

This implementation allows for multiple locations and manages the state of the checkboxes.

Comment on lines +133 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

Consider the following improvements:

  1. Implement state management for the location input and checkboxes.
  2. Allow for multiple location inputs.
  3. Add validation for the location input.

Here's an example implementation:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index: number,value: string)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div>

This implementation allows for multiple locations and manages the state of the checkboxes.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Application form URL</Subheading>
<Text>A link to your website (optional)</Text>
</div>
<Field>
<Input
id="app-url"
type="text"
autoComplete="url"
placeholder="https://example.com"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and state management for application form URL.

Add URL validation and state management for the application form URL input. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');constvalidateUrl=(url: string)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// Update the Input component:<Inputid="app-url"type="text"autoComplete="url"placeholder="https://example.com"value={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){// Handle invalid URL (e.g., show an error message)}}}/>

This implementation includes URL validation and manages the state of the application URL input.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Type</Subheading>
<Text>Full-time, part-time or freelancer</Text>
</div>
<Field>
<RadioGroup defaultValue="full_time">
<RadioField>
<Radio value="full_time" />
<Label>Full-time (€150)</Label>
<Description>Salaried Position</Description>
</RadioField>
<RadioField>
<Radio value="part_time" />
<Label>Part-time (€100)</Label>
<Description>
Salaried position but less than 4 days per week
</Description>
</RadioField>
<RadioField>
<Radio value="freelancer" />
<Label>Freelancer (€100)</Label>
<Description>Shorter-term usually or fixed term/job</Description>
</RadioField>
<RadioField>
<Radio value="other_role_type" />
<Label>Other (€100)</Label>
<Description>
Looking for a co-founder or something else we haven’t thought of
</Description>
</RadioField>
</RadioGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and radio button state management.

The structure of these sections is good, but consider the following improvements:

  1. Add URL validation for the application form URL input.
  2. Implement state management for the job type radio buttons.

Here's an example of how you could improve these sections:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');const[jobType,setJobType]=useState('full_time');constvalidateUrl=(url)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// In the JSX:<Inputvalue={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){alert('Please enter a valid URL');}}}/><RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation includes URL validation and manages the state of the job type selection.

Comment on lines +180 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement state management for job type selection.

Add state management for the job type radio buttons. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[jobType,setJobType]=useState('full_time');// Update the RadioGroup component:<RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation manages the state of the job type selection, allowing you to easily access the selected job type when submitting the form.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Terms & Conditions</Subheading>
<Text>Ah yes, the fine print.</Text>
</div>
<div className="space-y-2">
<Text>
By submitting this job listing, I acknowledge and agree to the
following terms:
</Text>
<Text>
<Strong>Content Restrictions:</Strong> My listing must not contain:{" "}
<br />- Adult or explicit content <br />- Fraudulent or illegitimate
work opportunities <br />- Inappropriate or offensive language
</Text>
<Text>
<Strong>Accurate Classification: </Strong>I confirm that the job
type (e.g., full-time, part-time, freelance) is correctly
categorized.
</Text>
<Text>
<Strong>Removal Policy:</Strong> I understand that my listing may be
removed without notice if it violates any of the above conditions.
</Text>
<Text>
<Strong>Refund Policy:</Strong> If my listing is removed due to a
violation within 7 days of posting, I may be eligible for a refund,
subject to review.
</Text>
<Text>
<Strong>Compliance:</Strong> I agree to comply with all applicable
laws and regulations regarding job postings and employment
practices.
</Text>
</div>
{/* Add error part after validation here */}
</section>
Comment on lines +218 to +256

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add a checkbox for terms and conditions acceptance.

To ensure users explicitly agree to the terms and conditions, add a checkbox at the end of this section. Here's an example implementation:

import{useState}from'react';// Inside the component:const[termsAccepted,setTermsAccepted]=useState(false);// After the terms and conditions text, add:<CheckboxField><Checkboxname="terms"checked={termsAccepted}onChange={(e)=>setTermsAccepted(e.target.checked)}/><Label>Ihavereadandagreetothetermsandconditions</Label></CheckboxField>

Then, in your form submission logic, you can check if termsAccepted is true before allowing the form to be submitted.


<Divider className="my-10" soft />

<div className="flex justify-end">
<Button className="rounded-md" color="pink">
Submit and checkout
</Button>
</div>
</form>
);
Comment on lines +258 to +266

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement form submission and checkout logic.

The submit button is correctly implemented, but there's no form submission or checkout logic. Consider the following improvements:

  1. Implement form validation before submission.
  2. Add error handling for the submission process.
  3. Integrate with a payment gateway for the checkout process.

Here's a basic example of how you could start implementing this:

import{useState}from'react';// Inside the component:const[isSubmitting,setIsSubmitting]=useState(false);consthandleSubmit=async(event: React.FormEvent)=>{event.preventDefault();setIsSubmitting(true);// Perform form validation heretry{// Submit form data to your APIconstresponse=awaitfetch('/api/job-postings',{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(formData),});if(!response.ok)thrownewError('Submission failed');// If submission is successful, proceed to checkout// Integrate with your payment gateway here// For example, redirect to a Stripe checkout pagewindow.location.href='/checkout';}catch(error){console.error('Error:',error);alert('An error occurred. Please try again.');}finally{setIsSubmitting(false);}};// Update the Button component:<ButtonclassName="rounded-md"color="pink"onClick={handleSubmit}disabled={isSubmitting}>{isSubmitting ? 'Submitting...' : 'Submit and checkout'}</Button>

This implementation includes basic form submission logic and error handling. You'll need to replace the placeholder API call and checkout process with your actual implementation.

}
7 changes: 7 additions & 0 deletions app/(app)/jobs/create/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
import Content from "./_client";

function page() {
return <Content />;
}

export default page;
Binary file addedpublic/images/company_placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions utils/flags.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { posthog } from "posthog-js";

export const FEATURE_FLAGS = {
FEATURE_FLAG_TEST: "feature-flag-test",
JOBS: "jobs",
// Add more feature flags as needed
} as const;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
267 changes: 267 additions & 0 deletions app/(app)/jobs/create/_client.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
"use client";

import { Button } from "@/components/ui-components/button";
import {
Checkbox,
CheckboxField,
CheckboxGroup,
} from "@/components/ui-components/checkbox";
import { Divider } from "@/components/ui-components/divider";
import { Description, Field, Label } from "@/components/ui-components/fieldset";
import { Heading, Subheading } from "@/components/ui-components/heading";
import { Input } from "@/components/ui-components/input";
import {
Radio,
RadioField,
RadioGroup,
} from "@/components/ui-components/radio";
import { Strong, Text } from "@/components/ui-components/text";
import { Textarea } from "@/components/ui-components/textarea";
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
import Image from "next/image";
import { notFound } from "next/navigation";
import React, { useRef, useState } from "react";

export default function Content() {
const flagEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
const fileInputRef = useRef<HTMLInputElement>(null);
const [imgUrl, setImgUrl] = useState<string | null>(null);

if (!flagEnabled) {
notFound();
}

return (
<form className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
<Heading level={1}>Post a job</Heading>
<Divider className="my-10 mt-6" />
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Logo</Subheading>
<Text>Square format is best</Text>
</div>
<Field>
<div className="flex items-center space-x-4">
<Image

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin A placeholder will be shown if no url is present

src={imgUrl || "/images/company_placeholder.png"}
width={80}
height={80}
alt="Company Logo"
className="rounded-[10px]"
/>
<div>
<Button
color="dark/white"
className="mt-3 rounded-md"
onClick={() => {
fileInputRef.current?.click();
}}
>
Change Logo
</Button>
<Input
type="file"
id="file-input"
name="company-logo"
accept="image/png, image/gif, image/jpeg"
onChange={() => {}}
className="hidden"
ref={fileInputRef}
/>
<Text className="mt-1 text-xs text-gray-500">
JPG, GIF or PNG. 1MB max.
</Text>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a grey square as a placeholder for the image which will be uploaded.
Otherwise there will be layout shift when an image is added.

We need to be able to see the preview of the image to be uploaded. This preview only needs to be in state. Have a look at the settings page for an example of how this is handled.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin Sure will do that way

</div>
</div>
</Field>
</section>
Comment on lines +34 to +77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement file upload functionality and validation.

The structure for the company logo upload is good, but there are a few improvements needed:

  1. The onChange handler for the file input is empty. Implement logic to handle file selection and update the image preview.
  2. Add validation for file type (JPG, GIF, PNG) and size (1MB max) as mentioned in the UI text.
  3. Update the image preview when a new file is selected.

Here's a suggested implementation:

consthandleFileChange=(event: React.ChangeEvent<HTMLInputElement>)=>{constfile=event.target.files?.[0];if(file){if(file.size>1024*1024){alert('File size should not exceed 1MB');return;}if(!['image/jpeg','image/gif','image/png'].includes(file.type)){alert('Only JPG, GIF, or PNG files are allowed');return;}constreader=newFileReader();reader.onload=(e)=>setImgUrl(e.target?.resultasstring);reader.readAsDataURL(file);}};// Update the Input component:<Inputtype="file"id="file-input"name="company-logo"accept="image/png, image/gif, image/jpeg"onChange={handleFileChange}className="hidden"ref={fileInputRef}/>


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Name</Subheading>
<Text>This will be shown in the format you type it</Text>
</div>
<Field>
<Input
id="company-name"
type="text"
placeholder="Pixel Pulse Studios"
autoComplete="given-company-name"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +95

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for company name.

The structure for the company name section is good, but consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register,formState: { errors }}=useForm();// Update the Input component:<Inputid="company-name"type="text"placeholder="Pixel Pulse Studios"autoComplete="given-company-name"{...register("companyName",{required: "Company name is required"})}/>{errors.companyName&&<span>{errors.companyName.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Title</Subheading>
<Text>The job title for the position that you are opening</Text>
</div>
<Field>
<Input
id="job-title"
type="text"
placeholder="Reality Architect"
autoComplete="given-job-title"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +113

@coderabbitaicoderabbitaiBotOct 12, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation.

The structure for company name and job title sections is consistent and well-organized. However, consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register, handleSubmit,formState: { errors }}=useForm();// In the JSX:<Input{...register("companyName",{required: "Company name is required"})}placeholder="Pixel Pulse Studios"/>{errors.companyName&&<span>{errors.companyName.message}</span>}<Input{...register("jobTitle",{required: "Job title is required"})}placeholder="Reality Architect"/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nil2000 I just noticed that we have no validation on the inputs. Would you add this to the list or would you rather if we merged this and you can do it as a next PR so it doesn't get stale.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NiallJoeMaher Considering Hacktoberfest It would be good for me to have a next PR and you can directly assign that to me 😅

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also love to progress with the other follow up issues mentioned in this issue

Comment on lines +97 to +113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for job title.

Similar to the company name section, implement form state management and validation for the job title. Using the same approach with react-hook-form:

// Update the Input component:<Inputid="job-title"type="text"placeholder="Reality Architect"autoComplete="given-job-title"{...register("jobTitle",{required: "Job title is required"})}/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide consistent form handling across the form fields.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Description</Subheading>
<Text>In markdown format</Text>
</div>
<Field>
<Textarea
id="job-description"
placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."
resizable={false}
rows={3}
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance job description input and implement validation.

  1. Implement form state management and validation for the job description, similar to previous sections.
  2. Consider making the textarea resizable or adjustable to accommodate longer job descriptions.

Here's an example implementation:

<Textareaid="job-description"placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."resizable={true}rows={3}{...register("jobDescription",{required: "Job description is required",minLength: {value: 50,message: "Job description should be at least 50 characters long"}})}/>{errors.jobDescription&&<span>{errors.jobDescription.message}</span>}

This allows for resizable input and adds minimum length validation.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Locations</Subheading>
<Text>
Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”).
</Text>
</div>
<Field>
<Input placeholder="Dublin (2 days in the office per week)" />
<CheckboxGroup className="mt-3">
<CheckboxField>
<Checkbox name="remote" value="is_remote" />
<Label>Work is remote</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="relocation" value="is_relocation_package" />
<Label>Relocation package given</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="visa" value="is_visa_sponsored" />
<Label>Visa sponsorship provided</Label>
</CheckboxField>
</CheckboxGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

The job description section looks good, but the locations section could be improved:

  1. Implement state management for the checkboxes.
  2. Consider allowing multiple location inputs or using a more structured approach for location data.
  3. Add validation for the location input.

Here's an example of how you could improve this section:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index,value)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex-1"><divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div></div>

This implementation allows for multiple locations and manages the state of the checkboxes.

Comment on lines +133 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

Consider the following improvements:

  1. Implement state management for the location input and checkboxes.
  2. Allow for multiple location inputs.
  3. Add validation for the location input.

Here's an example implementation:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index: number,value: string)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div>

This implementation allows for multiple locations and manages the state of the checkboxes.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Application form URL</Subheading>
<Text>A link to your website (optional)</Text>
</div>
<Field>
<Input
id="app-url"
type="text"
autoComplete="url"
placeholder="https://example.com"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and state management for application form URL.

Add URL validation and state management for the application form URL input. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');constvalidateUrl=(url: string)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// Update the Input component:<Inputid="app-url"type="text"autoComplete="url"placeholder="https://example.com"value={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){// Handle invalid URL (e.g., show an error message)}}}/>

This implementation includes URL validation and manages the state of the application URL input.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Type</Subheading>
<Text>Full-time, part-time or freelancer</Text>
</div>
<Field>
<RadioGroup defaultValue="full_time">
<RadioField>
<Radio value="full_time" />
<Label>Full-time (€150)</Label>
<Description>Salaried Position</Description>
</RadioField>
<RadioField>
<Radio value="part_time" />
<Label>Part-time (€100)</Label>
<Description>
Salaried position but less than 4 days per week
</Description>
</RadioField>
<RadioField>
<Radio value="freelancer" />
<Label>Freelancer (€100)</Label>
<Description>Shorter-term usually or fixed term/job</Description>
</RadioField>
<RadioField>
<Radio value="other_role_type" />
<Label>Other (€100)</Label>
<Description>
Looking for a co-founder or something else we haven’t thought of
</Description>
</RadioField>
</RadioGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and radio button state management.

The structure of these sections is good, but consider the following improvements:

  1. Add URL validation for the application form URL input.
  2. Implement state management for the job type radio buttons.

Here's an example of how you could improve these sections:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');const[jobType,setJobType]=useState('full_time');constvalidateUrl=(url)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// In the JSX:<Inputvalue={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){alert('Please enter a valid URL');}}}/><RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation includes URL validation and manages the state of the job type selection.

Comment on lines +180 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement state management for job type selection.

Add state management for the job type radio buttons. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[jobType,setJobType]=useState('full_time');// Update the RadioGroup component:<RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation manages the state of the job type selection, allowing you to easily access the selected job type when submitting the form.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Terms & Conditions</Subheading>
<Text>Ah yes, the fine print.</Text>
</div>
<div className="space-y-2">
<Text>
By submitting this job listing, I acknowledge and agree to the
following terms:
</Text>
<Text>
<Strong>Content Restrictions:</Strong> My listing must not contain:{" "}
<br />- Adult or explicit content <br />- Fraudulent or illegitimate
work opportunities <br />- Inappropriate or offensive language
</Text>
<Text>
<Strong>Accurate Classification: </Strong>I confirm that the job
type (e.g., full-time, part-time, freelance) is correctly
categorized.
</Text>
<Text>
<Strong>Removal Policy:</Strong> I understand that my listing may be
removed without notice if it violates any of the above conditions.
</Text>
<Text>
<Strong>Refund Policy:</Strong> If my listing is removed due to a
violation within 7 days of posting, I may be eligible for a refund,
subject to review.
</Text>
<Text>
<Strong>Compliance:</Strong> I agree to comply with all applicable
laws and regulations regarding job postings and employment
practices.
</Text>
</div>
{/* Add error part after validation here */}
</section>
Comment on lines +218 to +256

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add a checkbox for terms and conditions acceptance.

To ensure users explicitly agree to the terms and conditions, add a checkbox at the end of this section. Here's an example implementation:

import{useState}from'react';// Inside the component:const[termsAccepted,setTermsAccepted]=useState(false);// After the terms and conditions text, add:<CheckboxField><Checkboxname="terms"checked={termsAccepted}onChange={(e)=>setTermsAccepted(e.target.checked)}/><Label>Ihavereadandagreetothetermsandconditions</Label></CheckboxField>

Then, in your form submission logic, you can check if termsAccepted is true before allowing the form to be submitted.


<Divider className="my-10" soft />

<div className="flex justify-end">
<Button className="rounded-md" color="pink">
Submit and checkout
</Button>
</div>
</form>
);
Comment on lines +258 to +266

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement form submission and checkout logic.

The submit button is correctly implemented, but there's no form submission or checkout logic. Consider the following improvements:

  1. Implement form validation before submission.
  2. Add error handling for the submission process.
  3. Integrate with a payment gateway for the checkout process.

Here's a basic example of how you could start implementing this:

import{useState}from'react';// Inside the component:const[isSubmitting,setIsSubmitting]=useState(false);consthandleSubmit=async(event: React.FormEvent)=>{event.preventDefault();setIsSubmitting(true);// Perform form validation heretry{// Submit form data to your APIconstresponse=awaitfetch('/api/job-postings',{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(formData),});if(!response.ok)thrownewError('Submission failed');// If submission is successful, proceed to checkout// Integrate with your payment gateway here// For example, redirect to a Stripe checkout pagewindow.location.href='/checkout';}catch(error){console.error('Error:',error);alert('An error occurred. Please try again.');}finally{setIsSubmitting(false);}};// Update the Button component:<ButtonclassName="rounded-md"color="pink"onClick={handleSubmit}disabled={isSubmitting}>{isSubmitting ? 'Submitting...' : 'Submit and checkout'}</Button>

This implementation includes basic form submission logic and error handling. You'll need to replace the placeholder API call and checkout process with your actual implementation.

}
7 changes: 7 additions & 0 deletions app/(app)/jobs/create/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
import Content from "./_client";

function page() {
return <Content />;
}

export default page;
Binary file addedpublic/images/company_placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions utils/flags.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { posthog } from "posthog-js";

export const FEATURE_FLAGS = {
FEATURE_FLAG_TEST: "feature-flag-test",
JOBS: "jobs",
// Add more feature flags as needed
} as const;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
267 changes: 267 additions & 0 deletions app/(app)/jobs/create/_client.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
"use client";

import { Button } from "@/components/ui-components/button";
import {
Checkbox,
CheckboxField,
CheckboxGroup,
} from "@/components/ui-components/checkbox";
import { Divider } from "@/components/ui-components/divider";
import { Description, Field, Label } from "@/components/ui-components/fieldset";
import { Heading, Subheading } from "@/components/ui-components/heading";
import { Input } from "@/components/ui-components/input";
import {
Radio,
RadioField,
RadioGroup,
} from "@/components/ui-components/radio";
import { Strong, Text } from "@/components/ui-components/text";
import { Textarea } from "@/components/ui-components/textarea";
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
import Image from "next/image";
import { notFound } from "next/navigation";
import React, { useRef, useState } from "react";

export default function Content() {
const flagEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
const fileInputRef = useRef<HTMLInputElement>(null);
const [imgUrl, setImgUrl] = useState<string | null>(null);

if (!flagEnabled) {
notFound();
}

return (
<form className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
<Heading level={1}>Post a job</Heading>
<Divider className="my-10 mt-6" />
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Logo</Subheading>
<Text>Square format is best</Text>
</div>
<Field>
<div className="flex items-center space-x-4">
<Image

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin A placeholder will be shown if no url is present

src={imgUrl || "/images/company_placeholder.png"}
width={80}
height={80}
alt="Company Logo"
className="rounded-[10px]"
/>
<div>
<Button
color="dark/white"
className="mt-3 rounded-md"
onClick={() => {
fileInputRef.current?.click();
}}
>
Change Logo
</Button>
<Input
type="file"
id="file-input"
name="company-logo"
accept="image/png, image/gif, image/jpeg"
onChange={() => {}}
className="hidden"
ref={fileInputRef}
/>
<Text className="mt-1 text-xs text-gray-500">
JPG, GIF or PNG. 1MB max.
</Text>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a grey square as a placeholder for the image which will be uploaded.
Otherwise there will be layout shift when an image is added.

We need to be able to see the preview of the image to be uploaded. This preview only needs to be in state. Have a look at the settings page for an example of how this is handled.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@John-Paul-Larkin Sure will do that way

</div>
</div>
</Field>
</section>
Comment on lines +34 to +77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement file upload functionality and validation.

The structure for the company logo upload is good, but there are a few improvements needed:

  1. The onChange handler for the file input is empty. Implement logic to handle file selection and update the image preview.
  2. Add validation for file type (JPG, GIF, PNG) and size (1MB max) as mentioned in the UI text.
  3. Update the image preview when a new file is selected.

Here's a suggested implementation:

consthandleFileChange=(event: React.ChangeEvent<HTMLInputElement>)=>{constfile=event.target.files?.[0];if(file){if(file.size>1024*1024){alert('File size should not exceed 1MB');return;}if(!['image/jpeg','image/gif','image/png'].includes(file.type)){alert('Only JPG, GIF, or PNG files are allowed');return;}constreader=newFileReader();reader.onload=(e)=>setImgUrl(e.target?.resultasstring);reader.readAsDataURL(file);}};// Update the Input component:<Inputtype="file"id="file-input"name="company-logo"accept="image/png, image/gif, image/jpeg"onChange={handleFileChange}className="hidden"ref={fileInputRef}/>


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Company Name</Subheading>
<Text>This will be shown in the format you type it</Text>
</div>
<Field>
<Input
id="company-name"
type="text"
placeholder="Pixel Pulse Studios"
autoComplete="given-company-name"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +95

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for company name.

The structure for the company name section is good, but consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register,formState: { errors }}=useForm();// Update the Input component:<Inputid="company-name"type="text"placeholder="Pixel Pulse Studios"autoComplete="given-company-name"{...register("companyName",{required: "Company name is required"})}/>{errors.companyName&&<span>{errors.companyName.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Title</Subheading>
<Text>The job title for the position that you are opening</Text>
</div>
<Field>
<Input
id="job-title"
type="text"
placeholder="Reality Architect"
autoComplete="given-job-title"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +79 to +113

@coderabbitaicoderabbitaiBotOct 12, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation.

The structure for company name and job title sections is consistent and well-organized. However, consider implementing form state management and validation for a more robust user experience. You could use a library like react-hook-form or implement a custom solution.

Here's a basic example using react-hook-form:

import{useForm}from'react-hook-form';// Inside the component:const{ register, handleSubmit,formState: { errors }}=useForm();// In the JSX:<Input{...register("companyName",{required: "Company name is required"})}placeholder="Pixel Pulse Studios"/>{errors.companyName&&<span>{errors.companyName.message}</span>}<Input{...register("jobTitle",{required: "Job title is required"})}placeholder="Reality Architect"/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide basic form state management and required field validation. You can extend this to include more complex validation rules as needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nil2000 I just noticed that we have no validation on the inputs. Would you add this to the list or would you rather if we merged this and you can do it as a next PR so it doesn't get stale.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NiallJoeMaher Considering Hacktoberfest It would be good for me to have a next PR and you can directly assign that to me 😅

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also love to progress with the other follow up issues mentioned in this issue

Comment on lines +97 to +113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement form state management and validation for job title.

Similar to the company name section, implement form state management and validation for the job title. Using the same approach with react-hook-form:

// Update the Input component:<Inputid="job-title"type="text"placeholder="Reality Architect"autoComplete="given-job-title"{...register("jobTitle",{required: "Job title is required"})}/>{errors.jobTitle&&<span>{errors.jobTitle.message}</span>}

This will provide consistent form handling across the form fields.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Description</Subheading>
<Text>In markdown format</Text>
</div>
<Field>
<Textarea
id="job-description"
placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."
resizable={false}
rows={3}
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +131

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance job description input and implement validation.

  1. Implement form state management and validation for the job description, similar to previous sections.
  2. Consider making the textarea resizable or adjustable to accommodate longer job descriptions.

Here's an example implementation:

<Textareaid="job-description"placeholder="As a Reality Architect, you'll be at the forefront of creating immersive mixed reality experiences that blur the line between the digital and physical..."resizable={true}rows={3}{...register("jobDescription",{required: "Job description is required",minLength: {value: 50,message: "Job description should be at least 50 characters long"}})}/>{errors.jobDescription&&<span>{errors.jobDescription.message}</span>}

This allows for resizable input and adds minimum length validation.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Locations</Subheading>
<Text>
Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”).
</Text>
</div>
<Field>
<Input placeholder="Dublin (2 days in the office per week)" />
<CheckboxGroup className="mt-3">
<CheckboxField>
<Checkbox name="remote" value="is_remote" />
<Label>Work is remote</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="relocation" value="is_relocation_package" />
<Label>Relocation package given</Label>
</CheckboxField>
<CheckboxField>
<Checkbox name="visa" value="is_visa_sponsored" />
<Label>Visa sponsorship provided</Label>
</CheckboxField>
</CheckboxGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +115 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

The job description section looks good, but the locations section could be improved:

  1. Implement state management for the checkboxes.
  2. Consider allowing multiple location inputs or using a more structured approach for location data.
  3. Add validation for the location input.

Here's an example of how you could improve this section:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index,value)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex-1"><divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div></div>

This implementation allows for multiple locations and manages the state of the checkboxes.

Comment on lines +133 to +160

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance location handling and implement checkbox state management.

Consider the following improvements:

  1. Implement state management for the location input and checkboxes.
  2. Allow for multiple location inputs.
  3. Add validation for the location input.

Here's an example implementation:

import{useState}from'react';// Inside the component:const[locations,setLocations]=useState(['']);const[isRemote,setIsRemote]=useState(false);const[hasRelocation,setHasRelocation]=useState(false);const[hasVisa,setHasVisa]=useState(false);constaddLocation=()=>setLocations([...locations,'']);constupdateLocation=(index: number,value: string)=>{constnewLocations=[...locations];newLocations[index]=value;setLocations(newLocations);};// In the JSX:<divclassName="flex flex-col gap-4">{locations.map((location,index)=>(<Inputkey={index}value={location}onChange={(e)=>updateLocation(index,e.target.value)}placeholder="Dublin (2 days in the office per week)"/>))}<ButtononClick={addLocation}>AddAnotherLocation</Button><CheckboxGroup><CheckboxField><Checkboxname="remote"checked={isRemote}onChange={(e)=>setIsRemote(e.target.checked)}/><Label>Workisremote</Label></CheckboxField>{/* Similar changes for other checkboxes */}</CheckboxGroup></div>

This implementation allows for multiple locations and manages the state of the checkboxes.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Application form URL</Subheading>
<Text>A link to your website (optional)</Text>
</div>
<Field>
<Input
id="app-url"
type="text"
autoComplete="url"
placeholder="https://example.com"
/>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and state management for application form URL.

Add URL validation and state management for the application form URL input. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');constvalidateUrl=(url: string)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// Update the Input component:<Inputid="app-url"type="text"autoComplete="url"placeholder="https://example.com"value={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){// Handle invalid URL (e.g., show an error message)}}}/>

This implementation includes URL validation and manages the state of the application URL input.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Job Type</Subheading>
<Text>Full-time, part-time or freelancer</Text>
</div>
<Field>
<RadioGroup defaultValue="full_time">
<RadioField>
<Radio value="full_time" />
<Label>Full-time (€150)</Label>
<Description>Salaried Position</Description>
</RadioField>
<RadioField>
<Radio value="part_time" />
<Label>Part-time (€100)</Label>
<Description>
Salaried position but less than 4 days per week
</Description>
</RadioField>
<RadioField>
<Radio value="freelancer" />
<Label>Freelancer (€100)</Label>
<Description>Shorter-term usually or fixed term/job</Description>
</RadioField>
<RadioField>
<Radio value="other_role_type" />
<Label>Other (€100)</Label>
<Description>
Looking for a co-founder or something else we haven’t thought of
</Description>
</RadioField>
</RadioGroup>
</Field>
{/* Add error part after validation here */}
</section>
Comment on lines +162 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement URL validation and radio button state management.

The structure of these sections is good, but consider the following improvements:

  1. Add URL validation for the application form URL input.
  2. Implement state management for the job type radio buttons.

Here's an example of how you could improve these sections:

import{useState}from'react';// Inside the component:const[applicationUrl,setApplicationUrl]=useState('');const[jobType,setJobType]=useState('full_time');constvalidateUrl=(url)=>{constpattern=newRegExp('^(https?:\\/\\/)?'+// protocol'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+// domain name'((\\d{1,3}\\.){3}\\d{1,3}))'+// OR ip (v4) address'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+// port and path'(\\?[;&a-z\\d%_.~+=-]*)?'+// query string'(\\#[-a-z\\d_]*)?$','i');// fragment locatorreturn!!pattern.test(url);};// In the JSX:<Inputvalue={applicationUrl}onChange={(e)=>setApplicationUrl(e.target.value)}onBlur={()=>{if(applicationUrl&&!validateUrl(applicationUrl)){alert('Please enter a valid URL');}}}/><RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation includes URL validation and manages the state of the job type selection.

Comment on lines +180 to +216

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement state management for job type selection.

Add state management for the job type radio buttons. Here's a suggested implementation:

import{useState}from'react';// Inside the component:const[jobType,setJobType]=useState('full_time');// Update the RadioGroup component:<RadioGroupvalue={jobType}onChange={(value)=>setJobType(value)}>{/* ... existing radio buttons ... */}</RadioGroup>

This implementation manages the state of the job type selection, allowing you to easily access the selected job type when submitting the form.


<Divider className="my-10" soft />

<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="space-y-1">
<Subheading level={2}>Terms & Conditions</Subheading>
<Text>Ah yes, the fine print.</Text>
</div>
<div className="space-y-2">
<Text>
By submitting this job listing, I acknowledge and agree to the
following terms:
</Text>
<Text>
<Strong>Content Restrictions:</Strong> My listing must not contain:{" "}
<br />- Adult or explicit content <br />- Fraudulent or illegitimate
work opportunities <br />- Inappropriate or offensive language
</Text>
<Text>
<Strong>Accurate Classification: </Strong>I confirm that the job
type (e.g., full-time, part-time, freelance) is correctly
categorized.
</Text>
<Text>
<Strong>Removal Policy:</Strong> I understand that my listing may be
removed without notice if it violates any of the above conditions.
</Text>
<Text>
<Strong>Refund Policy:</Strong> If my listing is removed due to a
violation within 7 days of posting, I may be eligible for a refund,
subject to review.
</Text>
<Text>
<Strong>Compliance:</Strong> I agree to comply with all applicable
laws and regulations regarding job postings and employment
practices.
</Text>
</div>
{/* Add error part after validation here */}
</section>
Comment on lines +218 to +256

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add a checkbox for terms and conditions acceptance.

To ensure users explicitly agree to the terms and conditions, add a checkbox at the end of this section. Here's an example implementation:

import{useState}from'react';// Inside the component:const[termsAccepted,setTermsAccepted]=useState(false);// After the terms and conditions text, add:<CheckboxField><Checkboxname="terms"checked={termsAccepted}onChange={(e)=>setTermsAccepted(e.target.checked)}/><Label>Ihavereadandagreetothetermsandconditions</Label></CheckboxField>

Then, in your form submission logic, you can check if termsAccepted is true before allowing the form to be submitted.


<Divider className="my-10" soft />

<div className="flex justify-end">
<Button className="rounded-md" color="pink">
Submit and checkout
</Button>
</div>
</form>
);
Comment on lines +258 to +266

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement form submission and checkout logic.

The submit button is correctly implemented, but there's no form submission or checkout logic. Consider the following improvements:

  1. Implement form validation before submission.
  2. Add error handling for the submission process.
  3. Integrate with a payment gateway for the checkout process.

Here's a basic example of how you could start implementing this:

import{useState}from'react';// Inside the component:const[isSubmitting,setIsSubmitting]=useState(false);consthandleSubmit=async(event: React.FormEvent)=>{event.preventDefault();setIsSubmitting(true);// Perform form validation heretry{// Submit form data to your APIconstresponse=awaitfetch('/api/job-postings',{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(formData),});if(!response.ok)thrownewError('Submission failed');// If submission is successful, proceed to checkout// Integrate with your payment gateway here// For example, redirect to a Stripe checkout pagewindow.location.href='/checkout';}catch(error){console.error('Error:',error);alert('An error occurred. Please try again.');}finally{setIsSubmitting(false);}};// Update the Button component:<ButtonclassName="rounded-md"color="pink"onClick={handleSubmit}disabled={isSubmitting}>{isSubmitting ? 'Submitting...' : 'Submit and checkout'}</Button>

This implementation includes basic form submission logic and error handling. You'll need to replace the placeholder API call and checkout process with your actual implementation.

}
7 changes: 7 additions & 0 deletions app/(app)/jobs/create/page.tsx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
import Content from "./_client";

function page() {
return <Content />;
}

export default page;
Binary file addedpublic/images/company_placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions utils/flags.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { posthog } from "posthog-js";

export const FEATURE_FLAGS = {
FEATURE_FLAG_TEST: "feature-flag-test",
JOBS: "jobs",
// Add more feature flags as needed
} as const;

Expand Down