Skip to content

Commit e2e21e8

Browse files
committed
feat: refactor some parts
1 parent fdd1505 commit e2e21e8

12 files changed

Lines changed: 121 additions & 109 deletions

File tree

frontend/src/components/Slider.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@ const Slider = React.forwardRef<React.ElementRef<typeof SliderPrimitive.Root>, R
1616
<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full dark:bg-background-100 bg-pycon-custard-light">
1717
<SliderPrimitive.Range className="absolute h-full bg-pycon-orange" />
1818
</SliderPrimitive.Track>
19-
<SliderPrimitive.Thumb
20-
className="block h-8 w-8 bg-cover bg-center transition-transform hover:scale-110 focus-visible:outline-none disabled:opacity-50"
21-
style={{ backgroundImage: `url(${durian})` }}
22-
/>
19+
<SliderPrimitive.Thumb className="block relative size-4 rounded-full border border-primary/50 bg-background shadow-sm transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50">
20+
<div
21+
className="absolute -inset-x-1 -inset-y-1 size-6 bg-cover bg-no-repeat bg-center transition-transform hover:scale-110 focus-visible:outline-none disabled:opacity-50"
22+
style={{
23+
backgroundImage: `url(${durian})`
24+
}}
25+
/>
26+
</SliderPrimitive.Thumb>
2327
</SliderPrimitive.Root>
2428
)
2529
);

frontend/src/model/pycon/evaluations.ts

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,34 @@ export interface Evaluation {
4040
evaluationList: EvaluationResponse[];
4141
}
4242

43+
const sliderQuestions = [
44+
'how_would_you_rate_pycon_davao_overall',
45+
'how_satisfied_were_you_with_the_content_and_presentations',
46+
'how_likely_are_you_to_recommend_this_event_to_other_python_developers_or_enthusiasts_based_on_the_community_support_provided',
47+
'how_would_you_rate_event_organization_and_logistics',
48+
'were_the_event_schedule_and_timing_convenient_for_you',
49+
'did_you_find_opportunities_for_networking_valuable',
50+
'how_would_you_rate_the_networking_opportunities_provided',
51+
'how_likely_are_you_to_attend_future_pycon_davao_events',
52+
'were_the_venue_facilities_adequate'
53+
];
54+
55+
const textLongQuestions = [
56+
'what_was_the_highlight_of_the_event_for_you',
57+
'is_there_anything_specific_you_would_like_to_commend_about_the_event',
58+
'which_sessions_or_topics_did_you_find_most_valuable',
59+
'were_there_any_topics_or_sessions_you_felt_were_missing',
60+
'have_you_attended_python_events_before_if_so_what_kind_of_community_support_did_you_find_helpful_in_previous_events',
61+
'did_you_encounter_any_problems_with_organization_and_logistics',
62+
'what_could_have_been_improved_related_to_the_networking_and_interaction_aspects_of_the_event',
63+
'what_suggestions_do_you_have_for_improving_future_pycon_events',
64+
'is_there_anything_else_you_would_like_to_share_about_your_experience_at_the_event'
65+
];
66+
67+
const radioButtonQuestions: string[] = [];
68+
69+
export const PYCON_EVALUATION_QUESTIONS = [...sliderQuestions, ...textLongQuestions, ...radioButtonQuestions];
70+
4371
export const mapFormValuesToEvaluateCreate = (data: any) => {
4472
const values = { ...data };
4573
delete values.email;
@@ -50,31 +78,6 @@ export const mapFormValuesToEvaluateCreate = (data: any) => {
5078
export const convertToEvaluationList = (data: any) => {
5179
// Question type mappings
5280

53-
const sliderQuestions = [
54-
'how_would_you_rate_pycon_davao_overall',
55-
'how_satisfied_were_you_with_the_content_and_presentations',
56-
'how_likely_are_you_to_recommend_this_event_to_other_python_developers_or_enthusiasts_based_on_the_community_support_provided',
57-
'how_would_you_rate_event_organization_and_logistics',
58-
'were_the_event_schedule_and_timing_convenient_for_you',
59-
'did_you_find_opportunities_for_networking_valuable',
60-
'how_would_you_rate_the_networking_opportunities_provided',
61-
'how_likely_are_you_to_attend_future_pycon_davao_events'
62-
];
63-
64-
const textLongQuestions = [
65-
'what_was_the_highlight_of_the_event_for_you',
66-
'is_there_anything_specific_you_would_like_to_commend_about_the_event',
67-
'which_sessions_or_topics_did_you_find_most_valuable',
68-
'were_there_any_topics_or_sessions_you_felt_were_missing',
69-
'have_you_attended_python_events_before_if_so_what_kind_of_community_support_did_you_find_helpful_in_previous_events',
70-
'did_you_encounter_any_problems_with_organization_and_logistics',
71-
'what_could_have_been_improved_related_to_the_networking_and_interaction_aspects_of_the_event',
72-
'what_suggestions_do_you_have_for_improving_future_pycon_events',
73-
'is_there_anything_else_you_would_like_to_share_about_your_experience_at_the_event'
74-
];
75-
76-
const radioButtonQuestions = ['were_the_venue_facilities_adequate'];
77-
7881
return Object.keys(data).map((key) => {
7982
const response: Omit<EvaluationResponse, 'eventId' | 'createDate' | 'updateDate'> = {
8083
answer: null,

frontend/src/pages/client/pycon/evaluate/Evaluate.tsx

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { FC, useState } from 'react';
22
import { FormProvider } from 'react-hook-form';
33
import ErrorPage from '@/components/ErrorPage';
4-
import { FormDescription, FormError, FormItem, FormItemContainer, FormLabel } from '@/components/Form';
5-
import Input from '@/components/Input';
64
import Separator from '@/components/Separator';
75
import { cn } from '@/utils/classes';
86
import { useActiveBreakpoints } from '@/hooks/useActiveBreakpoints';
@@ -38,45 +36,51 @@ const Evaluate: FC<Props> = ({ eventId }) => {
3836
const showStepper = currentStep.id !== 'EventDetails' && currentStep.id !== 'ClaimCertificate';
3937

4038
return (
41-
<section className="flex flex-col items-center px-4">
42-
<div className="w-full max-w-6xl space-y-6 flex flex-col items-center">
39+
<section
40+
className={cn(
41+
'flex flex-col grow items-center px-4 h-full w-full text-pycon-custard font-nunito max-w-6xl mx-auto',
42+
currentStep.id === 'ClaimCertificate' && 'grow-0'
43+
)}
44+
>
45+
<div className="w-full h-full flex flex-col space-y-4 grow">
46+
{currentStep.id !== 'EventDetails' && currentStep.id !== 'ClaimCertificate' && <h1 className="text-xl">Evaluation</h1>}
47+
4348
<FormProvider {...form}>
44-
<div className="flex flex-col md:flex-row items-start gap-5 lg:gap-15 w-full lg:mt-10">
49+
<div className="flex flex-col md:flex-row w-full h-full grow">
4550
{showStepper && (
46-
<aside className="w-full md:w-1/4 md:min-w-[240px] lg:h-[50vh]">
47-
{showStepper && (
48-
<div className={cn('my-8', shouldBeVertical && 'h-[700px]')}>
49-
<Stepper
50-
orientation={shouldBeVertical ? 'vertical' : 'horizontal'}
51-
steps={STEPS}
52-
currentStep={currentStep}
53-
stepsToExclude={[STEP_CLAIM_CERTIFICATE]}
54-
/>
55-
</div>
56-
)}
57-
</aside>
51+
<div className={cn('my-8', shouldBeVertical && 'h-[700px]')}>
52+
<Stepper
53+
orientation={shouldBeVertical ? 'vertical' : 'horizontal'}
54+
steps={STEPS}
55+
currentStep={currentStep}
56+
stepsToExclude={[STEP_CLAIM_CERTIFICATE]}
57+
hideTitle
58+
/>
59+
</div>
5860
)}
5961

60-
<main className="flex-1">
61-
{currentStep.id !== 'EventDetails' && currentStep.title && <h1 className="text-xl text-center md:text-left mb-4">{currentStep.title}</h1>}
62-
<div className="space-y-4">
63-
{currentStep.id === 'EventDetails' && <EventDetails event={eventInfo} />}
64-
{currentStep.id === 'Evaluation_1' && <QuestionBuilder questions={EVALUATION_QUESTIONS_1} />}
65-
{currentStep.id === 'Evaluation_2' && <QuestionBuilder questions={EVALUATION_QUESTIONS_2} />}
66-
</div>
62+
<div
63+
className={cn(
64+
'space-y-4 grow',
65+
currentStep.id !== 'EventDetails' && currentStep.id !== 'ClaimCertificate' && shouldBeVertical && 'ms-[20vw] p-8'
66+
)}
67+
>
68+
{currentStep.id === 'EventDetails' && <EventDetails event={eventInfo} />}
69+
{currentStep.id === 'Evaluation_1' && <QuestionBuilder questions={EVALUATION_QUESTIONS_1} />}
70+
{currentStep.id === 'Evaluation_2' && <QuestionBuilder questions={EVALUATION_QUESTIONS_2} />}
71+
</div>
72+
</div>
6773

68-
{(currentStep.id === 'Evaluation_1' || currentStep.id === 'Evaluation_2') && <Separator className="my-4" />}
74+
{currentStep.id !== 'EventDetails' && currentStep.id !== 'ClaimCertificate' && <Separator className="my-4 bg-pycon-custard-light" />}
6975

70-
<EvaluateFooter
71-
event={eventInfo}
72-
steps={STEPS}
73-
currentStep={currentStep}
74-
fieldsToCheck={fieldsToCheck}
75-
setCurrentStep={setCurrentStep}
76-
submitForm={submit}
77-
/>
78-
</main>
79-
</div>
76+
<EvaluateFooter
77+
event={eventInfo}
78+
steps={STEPS}
79+
currentStep={currentStep}
80+
fieldsToCheck={fieldsToCheck}
81+
setCurrentStep={setCurrentStep}
82+
submitForm={submit}
83+
/>
8084

8185
{currentStep.id === 'ClaimCertificate' && <ClaimCertificate eventId={eventId!} />}
8286
</FormProvider>

frontend/src/pages/client/pycon/evaluate/PyconEvaluatePage.tsx renamed to frontend/src/pages/client/pycon/evaluate/EvaluatePage.tsx

File renamed without changes.

frontend/src/pages/client/pycon/evaluate/footer/EvaluateFooter.tsx

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Button from '@/components/Button';
22
import { Event } from '@/model/events';
3+
import { EventFooterPortal } from '../../register/footer/EventFooterPortal';
34
import { EvaluateStep } from '../steps/EvaluationSteps';
45
import useEvaluateFooter from './useEvaluateFooter';
56

@@ -28,28 +29,37 @@ const EvaluateFooter = <T extends string>({ event, steps, currentStep, fieldsToC
2829

2930
const eventDetailsFooter = () => {
3031
return (
31-
<Button
32-
onClick={onStartEvaluate}
33-
icon="ChevronRight"
34-
iconPlacement="right"
35-
className="py-6 sm:px-10 bg-pycon-orange hover:bg-pycon-custard cursor-pointer hover:text-pycon-orange"
36-
>
37-
Evaluate
38-
</Button>
32+
<EventFooterPortal>
33+
<Button
34+
onClick={onStartEvaluate}
35+
icon="ChevronRight"
36+
iconPlacement="right"
37+
iconClassname="stroke-pycon-violet!"
38+
className="cursor-pointer gap-x-2 bg-pycon-custard-light text-pycon-violet! rounded-full hover:bg-pycon-custard py-6 sm:px-10 my-8"
39+
>
40+
Evaluate
41+
</Button>
42+
</EventFooterPortal>
3943
);
4044
};
4145

4246
const evaluationFooter = () => {
4347
return (
4448
<>
45-
<Button onClick={onPrevStep} icon="ChevronLeft" className="py-6 sm:px-6 bg-pycon-orange hover:bg-pycon-custard cursor-pointer hover:text-pycon-orange">
49+
<Button
50+
onClick={onPrevStep}
51+
icon="ChevronLeft"
52+
strokeWidth={3}
53+
className="bg-transparent border border-pycon-custard-light text-pycon-custard-light font-medium rounded-full py-6 sm:px-6 hover:bg-pycon-custard-light cursor-pointer hover:text-pycon-violet"
54+
>
4655
Back
4756
</Button>
4857
<Button
4958
onClick={onNextStep}
5059
icon="ChevronRight"
60+
strokeWidth={3}
5161
iconPlacement="right"
52-
className="py-6 sm:px-6 bg-pycon-orange hover:bg-pycon-custard cursor-pointer hover:text-pycon-orange"
62+
className="bg-pycon-custard-light hover:bg-pycon-custard cursor-pointer text-pycon-violet rounded-full py-6 sm:px-6"
5363
>
5464
Next
5565
</Button>
@@ -62,9 +72,9 @@ const EvaluateFooter = <T extends string>({ event, steps, currentStep, fieldsToC
6272
<>
6373
<Button
6474
onClick={onPrevStep}
65-
disabled={isFormSubmitting}
6675
icon="ChevronLeft"
67-
className="py-6 sm:px-6 bg-pycon-orange hover:bg-pycon-custard cursor-pointer hover:text-pycon-orange"
76+
strokeWidth={3}
77+
className="bg-transparent border border-pycon-custard-light text-pycon-custard-light font-medium rounded-full py-6 sm:px-6 hover:bg-pycon-custard-light cursor-pointer hover:text-pycon-violet"
6878
>
6979
Back
7080
</Button>
@@ -73,7 +83,7 @@ const EvaluateFooter = <T extends string>({ event, steps, currentStep, fieldsToC
7383
loading={isFormSubmitting}
7484
icon="ChevronRight"
7585
iconPlacement="right"
76-
className="py-6 sm:px-6 bg-pycon-orange hover:bg-pycon-custard cursor-pointer hover:text-pycon-orange"
86+
className="bg-pycon-custard-light hover:bg-pycon-custard cursor-pointer text-pycon-violet rounded-full py-6 sm:px-6"
7787
>
7888
Submit
7989
</Button>

frontend/src/pages/client/pycon/evaluate/footer/useEvaluateFooter.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const useEvaluateFooter = <T extends string>(
2121
const { errorToast } = useNotifyToast();
2222
const api = useApi();
2323
const context = useCurrentUser();
24-
console.log(context);
2524
const { eventId } = event;
2625
const { trigger, getValues, setValue } = useFormContext<DefaultEvaluateFormValues>();
2726
const { isSubmitting: isFormSubmitting } = useFormState();
@@ -54,14 +53,6 @@ const useEvaluateFooter = <T extends string>(
5453
const onStartEvaluate = async () => {
5554
const email = context?.user?.email || getValues('email');
5655

57-
if (!email) {
58-
errorToast({
59-
title: 'Authentication Required',
60-
description: 'Please log in to continue.'
61-
});
62-
return;
63-
}
64-
6556
try {
6657
setIsValidatingEmail(true);
6758
const response = await api.execute(claimCertificate(eventId!, email));

frontend/src/pages/client/pycon/evaluate/questionBuilder/QuestionTypeSwitch.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const QuestionTypeSwitch = <TFieldValues extends FieldValues, TName extends Fiel
2121
return (
2222
<Select onValueChange={field.onChange} disabled={disabled}>
2323
<SelectTrigger>
24-
<SelectValue placeholder="Drop down Choices" />
24+
<SelectValue placeholder="Dropdown Choices" />
2525
</SelectTrigger>
2626
<SelectContent>
2727
<SelectGroup>
@@ -79,7 +79,15 @@ const QuestionTypeSwitch = <TFieldValues extends FieldValues, TName extends Fiel
7979
case 'slider':
8080
return (
8181
<div className="w-full">
82-
<Slider className="w-full mt-5" min={1} max={5} step={1} onValueChange={field.onChange} disabled={disabled} />
82+
<Slider
83+
className="w-full mt-5"
84+
min={1}
85+
max={5}
86+
step={1}
87+
value={Array.isArray(field.value) && !!field.value.length ? field.value : undefined}
88+
onValueChange={field.onChange}
89+
disabled={disabled}
90+
/>
8391
<div className="flex justify-between px-1 mt-5">
8492
{[...Array(5)].map((_, index) => (
8593
<span key={index}>{index + 1}</span>

frontend/src/pages/client/pycon/evaluate/questionBuilder/questionSchemaBuilder.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ export const questionSchemaBuilder = (questions: QuestionConfigItem[]) => {
66
(acc, question) => {
77
switch (question.questionType) {
88
case 'multiple_answers':
9-
acc[question.name] = z
10-
.array(z.string())
11-
12-
.min(1, { message: 'Please select at least one option' });
9+
acc[question.name] = z.array(z.string()).min(1, { message: 'Please select at least one option' });
1310
break;
1411

1512
case 'slider':

frontend/src/pages/client/pycon/evaluate/questionBuilder/questionsConfig.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export const EVALUATION_QUESTIONS_1: QuestionConfigItem[] = [
66
questionType: 'slider',
77
question: 'How would you rate PyCon Davao overall? (1–5)',
88
options: [],
9-
109
required: true
1110
},
1211
{
@@ -82,10 +81,9 @@ export const EVALUATION_QUESTIONS_2: QuestionConfigItem[] = [
8281
},
8382
{
8483
name: 'were_the_venue_facilities_adequate',
85-
questionType: 'radio_buttons',
86-
87-
question: 'Were the venue facilities adequate?',
88-
options: ['Yes', 'No'],
84+
questionType: 'slider',
85+
question: 'Were the venue facilities adequate? (1–5)',
86+
options: [],
8987
required: true
9088
},
9189
{

frontend/src/pages/client/pycon/evaluate/steps/ClaimCertificate.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ const ClaimCertificate: FC<Props> = ({ eventId }) => {
2424
// shareToLinkedIn(LinkedInParams);
2525
// };
2626

27-
console.log(certificateImgDataURL, isLoading);
28-
2927
if (isLoading) {
3028
return <Skeleton className="rounded-2xl h-[330px] w-full" />;
3129
}
@@ -38,10 +36,8 @@ const ClaimCertificate: FC<Props> = ({ eventId }) => {
3836

3937
return (
4038
<>
41-
<h3>Here's your Certificate!</h3>
42-
{certificateImgDataURL && (
43-
<img src={certificateImgDataURL} className="animate-[fade-in_3s_ease-in-out] rounded-2xl object-center object-cover w-full h-full" />
44-
)}
39+
<h2 className="text-center text-pycon-orange font-extrabold">Here's your Certificate!</h2>
40+
<img src={certificateImgDataURL} alt="certificate" className="animate-[fade-in_3s_ease-in-out] rounded-2xl object-center object-cover w-full h-full" />
4541
<div className="w-full space-y-10">
4642
<div className="flex flex-col space-y-4">
4743
<Button onClick={onDownloadImg} icon="Download" variant="secondaryGradient" className="py-3 px-6">
@@ -56,9 +52,9 @@ const ClaimCertificate: FC<Props> = ({ eventId }) => {
5652
Share to LinkedIn
5753
</Button> */}
5854

59-
<Button onClick={reloadPage} icon="ChevronRight" iconPlacement="right" className="w-full py-3 px-6">
55+
{/* <Button onClick={reloadPage} icon="ChevronRight" iconPlacement="right" className="w-full py-3 px-6">
6056
Evaluate with another user
61-
</Button>
57+
</Button> */}
6258
</div>
6359
</>
6460
);

0 commit comments

Comments
 (0)