Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 167
UI part done for posting jobs#1106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
048fb93fbb7bb7883ec805897e873fcf0326465e958761907adc9d4f8ec431b149d1a186521ea2eabb2177f72d5File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff 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 | ||
| 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> | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. 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. ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement file upload functionality and validation. The structure for the company logo upload is good, but there are a few improvements needed:
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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 Here's a basic example using 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
| ||
| <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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance job description input and implement validation.
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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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 | ||
| <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
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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:
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. | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import Content from "./_client"; | ||
| function page() { | ||
| return <Content />; | ||
| } | ||
| export default page; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@John-Paul-Larkin A
placeholderwill be shown if nourlis present