Skip to content

Commit 2f28f95

Browse files
Merge branch 'develop' into 1115-tags-in-home-page-not-matching-style
2 parents 2b229ca + dd63fd5 commit 2f28f95

File tree

24 files changed

+869
-122
lines changed

24 files changed

+869
-122
lines changed

app/(app)/create/[[...paramsArr]]/_client.tsx

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ import copy from "copy-to-clipboard";
2929
import { PostStatus, getPostStatus, isValidScheduleTime } from "@/utils/post";
3030
import { ImageUp, LoaderCircle } from "lucide-react";
3131
import { uploadFile } from "@/utils/s3helpers";
32-
import { type Session } from "next-auth";
32+
import { getUploadUrl } from "@/app/actions/getUploadUrl";
3333

34-
const Create = ({ session }: { session: Session }) => {
34+
const Create = () => {
3535
const params = useParams();
3636
const router = useRouter();
3737

@@ -71,29 +71,40 @@ const Create = ({ session }: { session: Session }) => {
7171
const file = e.target.files[0];
7272
const { size, type } = file;
7373

74-
await getUploadUrl(
75-
{ size, type, config: { kind: "uploads", userId: session.user?.id } },
76-
{
77-
onError(error) {
78-
setUploadStatus("error");
79-
if (error) return toast.error(error.message);
80-
return toast.error(
81-
"Something went wrong uploading the photo, please retry.",
82-
);
83-
},
84-
async onSuccess(signedUrl) {
85-
const { fileLocation } = await uploadFile(signedUrl, file);
86-
if (!fileLocation) {
87-
setUploadStatus("error");
88-
return toast.error(
89-
"Something went wrong uploading the photo, please retry.",
90-
);
91-
}
92-
setUploadStatus("success");
93-
setUploadUrl(fileLocation);
94-
},
95-
},
96-
);
74+
try {
75+
const res = await getUploadUrl({
76+
size,
77+
type,
78+
uploadType: "uploads",
79+
});
80+
81+
const signedUrl = res?.data;
82+
83+
if (!signedUrl) {
84+
setUploadStatus("error");
85+
return toast.error(
86+
"Something went wrong uploading the photo, please retry.",
87+
);
88+
}
89+
90+
const { fileLocation } = await uploadFile(signedUrl, file);
91+
if (!fileLocation) {
92+
setUploadStatus("error");
93+
return toast.error(
94+
"Something went wrong uploading the photo, please retry.",
95+
);
96+
}
97+
setUploadStatus("success");
98+
setUploadUrl(fileLocation);
99+
} catch (error) {
100+
setUploadStatus("error");
101+
toast.error(
102+
error instanceof Error
103+
? error.message
104+
: "An error occurred while uploading the image.",
105+
);
106+
Sentry.captureException(error);
107+
}
97108
}
98109
};
99110

@@ -162,8 +173,6 @@ const Create = ({ session }: { session: Session }) => {
162173
},
163174
);
164175

165-
const { mutate: getUploadUrl } = api.event.getUploadUrl.useMutation();
166-
167176
const PREVIEW_URL = `${process.env.NODE_ENV === "development" ? "http://localhost:3000" : "https://www.codu.co"}/draft/${postId}`;
168177
const UPLOADED_IMAGE_URL = `![Image description](${uploadUrl})`;
169178

app/(app)/jobs/create/_client.tsx

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
"use client";
2+
3+
import { Button } from "@/components/ui-components/button";
4+
import {
5+
Checkbox,
6+
CheckboxField,
7+
CheckboxGroup,
8+
} from "@/components/ui-components/checkbox";
9+
import { Divider } from "@/components/ui-components/divider";
10+
import { Description, Field, Label } from "@/components/ui-components/fieldset";
11+
import { Heading, Subheading } from "@/components/ui-components/heading";
12+
import { Input } from "@/components/ui-components/input";
13+
import {
14+
Radio,
15+
RadioField,
16+
RadioGroup,
17+
} from "@/components/ui-components/radio";
18+
import { Strong, Text } from "@/components/ui-components/text";
19+
import { Textarea } from "@/components/ui-components/textarea";
20+
import { FEATURE_FLAGS, isFlagEnabled } from "@/utils/flags";
21+
import Image from "next/image";
22+
import { notFound } from "next/navigation";
23+
import React, { useRef, useState } from "react";
24+
25+
export default function Content() {
26+
const flagEnabled = isFlagEnabled(FEATURE_FLAGS.JOBS);
27+
const fileInputRef = useRef<HTMLInputElement>(null);
28+
const [imgUrl, setImgUrl] = useState<string | null>(null);
29+
30+
if (!flagEnabled) {
31+
notFound();
32+
}
33+
34+
return (
35+
<form className="mx-auto max-w-4xl p-3 pt-8 sm:px-4">
36+
<Heading level={1}>Post a job</Heading>
37+
<Divider className="my-10 mt-6" />
38+
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
39+
<div className="space-y-1">
40+
<Subheading level={2}>Company Logo</Subheading>
41+
<Text>Square format is best</Text>
42+
</div>
43+
<Field>
44+
<div className="flex items-center space-x-4">
45+
<Image
46+
src={imgUrl || "/images/company_placeholder.png"}
47+
width={80}
48+
height={80}
49+
alt="Company Logo"
50+
className="rounded-[10px]"
51+
/>
52+
<div>
53+
<Button
54+
color="dark/white"
55+
className="mt-3 rounded-md"
56+
onClick={() => {
57+
fileInputRef.current?.click();
58+
}}
59+
>
60+
Change Logo
61+
</Button>
62+
<Input
63+
type="file"
64+
id="file-input"
65+
name="company-logo"
66+
accept="image/png, image/gif, image/jpeg"
67+
onChange={() => {}}
68+
className="hidden"
69+
ref={fileInputRef}
70+
/>
71+
<Text className="mt-1 text-xs text-gray-500">
72+
JPG, GIF or PNG. 1MB max.
73+
</Text>
74+
</div>
75+
</div>
76+
</Field>
77+
</section>
78+
79+
<Divider className="my-10" soft />
80+
81+
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
82+
<div className="space-y-1">
83+
<Subheading level={2}>Company Name</Subheading>
84+
<Text>This will be shown in the format you type it</Text>
85+
</div>
86+
<Field>
87+
<Input
88+
id="company-name"
89+
type="text"
90+
placeholder="Pixel Pulse Studios"
91+
autoComplete="given-company-name"
92+
/>
93+
</Field>
94+
{/* Add error part after validation here */}
95+
</section>
96+
97+
<Divider className="my-10" soft />
98+
99+
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
100+
<div className="space-y-1">
101+
<Subheading level={2}>Job Title</Subheading>
102+
<Text>The job title for the position that you are opening</Text>
103+
</div>
104+
<Field>
105+
<Input
106+
id="job-title"
107+
type="text"
108+
placeholder="Reality Architect"
109+
autoComplete="given-job-title"
110+
/>
111+
</Field>
112+
{/* Add error part after validation here */}
113+
</section>
114+
115+
<Divider className="my-10" soft />
116+
117+
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
118+
<div className="space-y-1">
119+
<Subheading level={2}>Job Description</Subheading>
120+
<Text>In markdown format</Text>
121+
</div>
122+
<Field>
123+
<Textarea
124+
id="job-description"
125+
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..."
126+
resizable={false}
127+
rows={3}
128+
/>
129+
</Field>
130+
{/* Add error part after validation here */}
131+
</section>
132+
133+
<Divider className="my-10" soft />
134+
135+
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
136+
<div className="space-y-1">
137+
<Subheading level={2}>Locations</Subheading>
138+
<Text>
139+
Where is the job location? (“Dublin”, “Remote USA”, “Anywhere”).
140+
</Text>
141+
</div>
142+
<Field>
143+
<Input placeholder="Dublin (2 days in the office per week)" />
144+
<CheckboxGroup className="mt-3">
145+
<CheckboxField>
146+
<Checkbox name="remote" value="is_remote" />
147+
<Label>Work is remote</Label>
148+
</CheckboxField>
149+
<CheckboxField>
150+
<Checkbox name="relocation" value="is_relocation_package" />
151+
<Label>Relocation package given</Label>
152+
</CheckboxField>
153+
<CheckboxField>
154+
<Checkbox name="visa" value="is_visa_sponsored" />
155+
<Label>Visa sponsorship provided</Label>
156+
</CheckboxField>
157+
</CheckboxGroup>
158+
</Field>
159+
{/* Add error part after validation here */}
160+
</section>
161+
162+
<Divider className="my-10" soft />
163+
164+
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
165+
<div className="space-y-1">
166+
<Subheading level={2}>Application form URL</Subheading>
167+
<Text>A link to your website (optional)</Text>
168+
</div>
169+
<Field>
170+
<Input
171+
id="app-url"
172+
type="text"
173+
autoComplete="url"
174+
placeholder="https://example.com"
175+
/>
176+
</Field>
177+
{/* Add error part after validation here */}
178+
</section>
179+
180+
<Divider className="my-10" soft />
181+
182+
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
183+
<div className="space-y-1">
184+
<Subheading level={2}>Job Type</Subheading>
185+
<Text>Full-time, part-time or freelancer</Text>
186+
</div>
187+
<Field>
188+
<RadioGroup defaultValue="full_time">
189+
<RadioField>
190+
<Radio value="full_time" />
191+
<Label>Full-time (€150)</Label>
192+
<Description>Salaried Position</Description>
193+
</RadioField>
194+
<RadioField>
195+
<Radio value="part_time" />
196+
<Label>Part-time (€100)</Label>
197+
<Description>
198+
Salaried position but less than 4 days per week
199+
</Description>
200+
</RadioField>
201+
<RadioField>
202+
<Radio value="freelancer" />
203+
<Label>Freelancer (€100)</Label>
204+
<Description>Shorter-term usually or fixed term/job</Description>
205+
</RadioField>
206+
<RadioField>
207+
<Radio value="other_role_type" />
208+
<Label>Other (€100)</Label>
209+
<Description>
210+
Looking for a co-founder or something else we haven’t thought of
211+
</Description>
212+
</RadioField>
213+
</RadioGroup>
214+
</Field>
215+
{/* Add error part after validation here */}
216+
</section>
217+
218+
<Divider className="my-10" soft />
219+
220+
<section className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
221+
<div className="space-y-1">
222+
<Subheading level={2}>Terms & Conditions</Subheading>
223+
<Text>Ah yes, the fine print.</Text>
224+
</div>
225+
<div className="space-y-2">
226+
<Text>
227+
By submitting this job listing, I acknowledge and agree to the
228+
following terms:
229+
</Text>
230+
<Text>
231+
<Strong>Content Restrictions:</Strong> My listing must not contain:{" "}
232+
<br />- Adult or explicit content <br />- Fraudulent or illegitimate
233+
work opportunities <br />- Inappropriate or offensive language
234+
</Text>
235+
<Text>
236+
<Strong>Accurate Classification: </Strong>I confirm that the job
237+
type (e.g., full-time, part-time, freelance) is correctly
238+
categorized.
239+
</Text>
240+
<Text>
241+
<Strong>Removal Policy:</Strong> I understand that my listing may be
242+
removed without notice if it violates any of the above conditions.
243+
</Text>
244+
<Text>
245+
<Strong>Refund Policy:</Strong> If my listing is removed due to a
246+
violation within 7 days of posting, I may be eligible for a refund,
247+
subject to review.
248+
</Text>
249+
<Text>
250+
<Strong>Compliance:</Strong> I agree to comply with all applicable
251+
laws and regulations regarding job postings and employment
252+
practices.
253+
</Text>
254+
</div>
255+
{/* Add error part after validation here */}
256+
</section>
257+
258+
<Divider className="my-10" soft />
259+
260+
<div className="flex justify-end">
261+
<Button className="rounded-md" color="pink">
262+
Submit and checkout
263+
</Button>
264+
</div>
265+
</form>
266+
);
267+
}

app/(app)/jobs/create/page.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Content from "./_client";
2+
3+
function page() {
4+
return <Content />;
5+
}
6+
7+
export default page;

0 commit comments

Comments
 (0)