-
-
Notifications
You must be signed in to change notification settings - Fork 170
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
Changes from 2 commits
048fb93
fbb7bb7
883ec80
5897e87
3fcf032
6465e95
8761907
adc9d4f
8ec431b
149d1a1
86521ea
2eabb21
77f72d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,227 @@ | ||
| "use client"; | ||
|
|
||
| import { Button } from "@/components/ui-components/button"; | ||
| import { | ||
| Checkbox, | ||
| CheckboxField, | ||
| CheckboxGroup, | ||
| } from "@/components/ui-components/checkbox"; | ||
| import { Description, Label } from "@/components/ui-components/fieldset"; | ||
| import { Heading } 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 Image from "next/image"; | ||
| import React, { useRef } from "react"; | ||
|
|
||
| export default function Content() { | ||
| const fileInputRef = useRef<HTMLInputElement>(null); | ||
| return ( | ||
| <div className="flex justify-center"> | ||
| <div className="flex flex-col gap-y-10 pt-6 md:w-[1000px]"> | ||
| <Heading level={1}>Post a job</Heading> | ||
| <div className="flex flex-row justify-between"> | ||
| <div className="flex flex-1 flex-col gap-1 text-sm"> | ||
| <Text> | ||
| <Strong>Company Logo</Strong> | ||
| </Text> | ||
| <Text>Square format is best</Text> | ||
| </div> | ||
| <div className="flex-1"> | ||
| <div className="flex flex-row gap-3"> | ||
| <Image | ||
| src="https://s3-alpha-sig.figma.com/img/8a23/cb6a/8d462a922529d9ae7a44772fb9f64b61?Expires=1729468800&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=XnJwSdtoT2ZlVsJvhBPWF3AAxyOJ5qVcunVwoDqMLar78R6wuZUJvkxS3VqeOFued9~gWF8biRwIdWhSA4NHF9Fiw5P5S-KFzs68QXDGLYVL7AhoEA2u-GYaEYep52BRmsQWceF8Bd9IDPYceJkF7MyIQCIkJFkuZ6FvXcHa319yBMk0xS4qGux2sNiBqxXOjA9gcraKuBh~mj3bEQ9l4GrqzBeHRt1s6OaBqbIJUSic984Wfizmfyjcu7NDLxJaTVsYVhe8d5p2Sv8QVCrvc0UspSGLYpsmJjybLF41zoEEkIxSb~iX905tpAo2q757TKSTDOinzLdCcUwCJ-VZ8Q__" | ||
| width={80} | ||
| height={80} | ||
| alt="Company Logo" | ||
| className="rounded-[10px]" | ||
| /> | ||
| <div> | ||
| {/* Need to do the file selection logic using ref as well */} | ||
| <Button | ||
| color="dark/white" | ||
| className="mt-3 rounded-md" | ||
| onClick={() => { | ||
| fileInputRef.current?.click(); | ||
| }} | ||
| > | ||
| <input type="file" hidden ref={fileInputRef} /> | ||
| Change Logo | ||
| </Button> | ||
| <p className="mt-1 text-xs text-[#888888]"> | ||
| JPG, GIF or PNG. 1MB max. | ||
| </p> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div className="flex flex-row justify-between"> | ||
| <div className="flex flex-1 flex-col gap-1 text-sm"> | ||
| <Text> | ||
| <Strong>Company Name</Strong> | ||
| </Text> | ||
| <Text>This will be shown in the format you type it</Text> | ||
| </div> | ||
| <div className="flex-1"> | ||
| <Input placeholder="Pixel Pulse Studios" /> | ||
| </div> | ||
| </div> | ||
| <div className="flex flex-row justify-between"> | ||
| <div className="flex flex-1 flex-col gap-1 text-sm"> | ||
| <Text> | ||
| <Strong>Job Title</Strong> | ||
| </Text> | ||
| <Text>The job title for the position that you are opening</Text> | ||
| </div> | ||
| <div className="flex-1"> | ||
| <Input placeholder="Reality Architect" /> | ||
| </div> | ||
| </div> | ||
| <div className="flex flex-row justify-between"> | ||
| <div className="flex flex-1 flex-col gap-1 text-sm"> | ||
| <Text> | ||
| <Strong>Job Description</Strong> | ||
| </Text> | ||
| <Text>In markdown format</Text> | ||
| </div> | ||
| <div className="flex-1"> | ||
| <Textarea | ||
| 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} | ||
| /> | ||
| </div> | ||
| </div> | ||
|
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. The form fields for company name, job title, and job description are implemented correctly. However, there's no form state management or validation in place. Consider using a form library like Formik or react-hook-form for managing form state and validation. Here's a basic example using react-hook-form: import { useForm } from 'react-hook-form';
// Inside the component:
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => console.log(data);
// In the JSX:
<form onSubmit={handleSubmit(onSubmit)}>
<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>}
<Textarea
{...register("jobDescription", { required: "Job description is required" })}
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}
/>
{errors.jobDescription && <span>{errors.jobDescription.message}</span>}
</form>This will provide basic form state management and required field validation. |
||
| <div className="flex flex-row justify-between"> | ||
| <div className="flex flex-1 flex-col gap-1 text-sm"> | ||
| <Text> | ||
| <Strong>Locations</Strong> | ||
| </Text> | ||
| <Text> | ||
| Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”). | ||
| </Text> | ||
| </div> | ||
| <div className="flex-1"> | ||
| <div className="flex flex-col gap-4"> | ||
| <Input placeholder="Dublin (2 days in the office per week)" /> | ||
| <CheckboxGroup> | ||
| <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> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
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 locations section is implemented correctly, but it could benefit from some improvements:
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);
const addLocation = () => setLocations([...locations, '']);
const updateLocation = (index, value) => {
const newLocations = [...locations];
newLocations[index] = value;
setLocations(newLocations);
};
// In the JSX:
<div className="flex-1">
<div className="flex flex-col gap-4">
{locations.map((location, index) => (
<Input
key={index}
value={location}
onChange={(e) => updateLocation(index, e.target.value)}
placeholder="Dublin (2 days in the office per week)"
/>
))}
<Button onClick={addLocation}>Add Another Location</Button>
<CheckboxGroup>
<CheckboxField>
<Checkbox
name="remote"
value="is_remote"
checked={isRemote}
onChange={(e) => setIsRemote(e.target.checked)}
/>
<Label>Work is remote</Label>
</CheckboxField>
<CheckboxField>
<Checkbox
name="relocation"
value="is_relocation_package"
checked={hasRelocation}
onChange={(e) => setHasRelocation(e.target.checked)}
/>
<Label>Relocation package given</Label>
</CheckboxField>
<CheckboxField>
<Checkbox
name="visa"
value="is_visa_sponsored"
checked={hasVisa}
onChange={(e) => setHasVisa(e.target.checked)}
/>
<Label>Visa sponsorship provided</Label>
</CheckboxField>
</CheckboxGroup>
</div>
</div>This implementation allows for multiple locations and manages the state of the checkboxes. |
||
| <div className="flex flex-row justify-between"> | ||
| <div className="flex flex-1 flex-col gap-1 text-sm"> | ||
| <Text> | ||
| <Strong>Application form URL</Strong> | ||
| </Text> | ||
| <Text>A link to your website (optional)</Text> | ||
| </div> | ||
| <div className="flex-1"> | ||
| <Input /> | ||
| </div> | ||
| </div> | ||
| <div className="flex flex-row justify-between"> | ||
| <div className="flex flex-1 flex-col gap-1 text-sm"> | ||
| <Text> | ||
| <Strong>Job Type</Strong> | ||
| </Text> | ||
| <Text>Full-time, part-time or freelancer</Text> | ||
| </div> | ||
| <div className="flex-1"> | ||
| <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> | ||
| </div> | ||
|
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 application form URL and job type sections are implemented correctly, but could be improved:
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');
const validateUrl = (url) => {
const pattern = new RegExp('^(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 locator
return !!pattern.test(url);
};
// In the JSX:
<div className="flex-1">
<Input
value={applicationUrl}
onChange={(e) => setApplicationUrl(e.target.value)}
onBlur={() => {
if (applicationUrl && !validateUrl(applicationUrl)) {
alert('Please enter a valid URL');
}
}}
/>
</div>
<div className="flex-1">
<RadioGroup
value={jobType}
onChange={(value) => setJobType(value)}
>
<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>
</div>This implementation includes URL validation and manages the state of the job type selection. |
||
| </div> | ||
| <div className="flex flex-row justify-between"> | ||
| <div className="flex flex-1 flex-col gap-1 text-sm"> | ||
| <Text> | ||
| <Strong>Terms & Conditions</Strong> | ||
| </Text> | ||
| <Text>Ah yes, the fine print.</Text> | ||
| </div> | ||
| <div className="flex flex-1 flex-col gap-1"> | ||
| <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> | ||
|
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. The terms and conditions are clearly presented, but there's no mechanism for the user to explicitly accept them. Consider adding a checkbox that the user must check to indicate they've read and agreed to the terms. Here's an example of how you could implement this: import { useState } from 'react';
// Inside the component:
const [termsAccepted, setTermsAccepted] = useState(false);
// After the terms and conditions text, add:
<CheckboxField>
<Checkbox
name="terms"
checked={termsAccepted}
onChange={(e) => setTermsAccepted(e.target.checked)}
/>
<Label>I have read and agree to the terms and conditions</Label>
</CheckboxField>Then, in your form submission logic, you can check if |
||
| </div> | ||
| <div className="flex justify-end"> | ||
| <Button className="rounded-md" color="pink"> | ||
| Submit and checkout | ||
| </Button> | ||
| </div> | ||
|
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);
const handleSubmit = async (event) => {
event.preventDefault();
setIsSubmitting(true);
// Perform form validation here
try {
// Submit form data to your API
const response = await fetch('/api/job-postings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (!response.ok) throw new Error('Submission failed');
// If submission is successful, proceed to checkout
// Integrate with your payment gateway here
// For example, redirect to a Stripe checkout page
window.location.href = '/checkout';
} catch (error) {
console.error('Error:', error);
alert('An error occurred. Please try again.');
} finally {
setIsSubmitting(false);
}
};
// In the JSX:
<Button
className="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. |
||
| </div> | ||
| </div> | ||
| ); | ||
|
Comment on lines
+26
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 state management and validation. While the form structure is well-implemented, it currently lacks global state management and field validation. This could lead to submission of incomplete or invalid data. Consider using a form library like react-hook-form to manage form state and implement validation. Here's a basic example of how you could implement this using react-hook-form: import { useForm } from 'react-hook-form';
export default function Content() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => {
console.log(data);
// Implement your submission logic here
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
{/* ... other form elements ... */}
<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>}
<Textarea
{...register("jobDescription", { required: "Job description is required" })}
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}
/>
{errors.jobDescription && <span>{errors.jobDescription.message}</span>}
{/* ... other form elements ... */}
<Button type="submit" className="rounded-md" color="pink">
Submit and checkout
</Button>
</form>
);
}This implementation provides basic form state management and required field validation. You can extend this to include more complex validation rules as needed.
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);
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
setIsSubmitting(true);
// Perform form validation here
try {
// Submit form data to your API
const response = await fetch('/api/job-postings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (!response.ok) throw new Error('Submission failed');
// If submission is successful, proceed to checkout
// Integrate with your payment gateway here
// For example, redirect to a Stripe checkout page
window.location.href = '/checkout';
} catch (error) {
console.error('Error:', error);
alert('An error occurred. Please try again.');
} finally {
setIsSubmitting(false);
}
};
// Update the Button component:
<Button
className="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; |
|
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 dont need this page yet, so could you remove it from this PR.
Contributor
Author
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. Got it
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. I think this file being removed is one of the only things left |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import React from "react"; | ||
|
|
||
| function page() { | ||
| return <div>Jobs first page</div>; | ||
|
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. Component content doesn't match PR objectives The current implementation seems to be a placeholder and doesn't align with the PR objectives of creating a job posting form. According to the PR description, this component should render a form for entering job postings. Consider implementing the job posting form as described in the linked issue #1082. The form should include fields for company information and job specifications, and should be responsive. Utilize existing components from the codebase where possible. Would you like assistance in scaffolding the basic structure for the job posting form? |
||
| } | ||
|
|
||
| export default page; | ||
|
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 Consider adding TypeScript type annotations To improve code maintainability and catch potential errors early, consider adding TypeScript type annotations to this component. Here's an example of how you could add types: import React from "react";
interface JobPostingFormProps {
// Add any props here if needed
}
function Page({}: JobPostingFormProps): React.ReactElement {
return <div>Jobs first page</div>;
}
export default Page;This change introduces a |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ const REMOTE_PATTERNS = [ | |
| // Temporary wildcard | ||
| "*.s3.eu-west-1.amazonaws.com", | ||
| "s3.eu-west-1.amazonaws.com", | ||
| "s3-alpha-sig.figma.com", //Added for Figma | ||
|
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. No need for a placeholder image so we can remove this. A person should be able to see an empty placeholder and then a preview when they upload.
Contributor
Author
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. Ok will remove that as well |
||
| ].map((hostname) => ({ | ||
| hostname, | ||
| protocol: "https", | ||
|
|
||
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.
Implement file selection logic and add validation.
The logo upload functionality is incomplete. Consider the following improvements:
ref.Here's a basic implementation to get you started: