Skip to content

Commit

Permalink
refactor(ui): poll cardgroup
Browse files Browse the repository at this point in the history
  • Loading branch information
sawaYch committed Mar 1, 2024
1 parent c361047 commit e7888a0
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 153 deletions.
50 changes: 50 additions & 0 deletions components/new-poll-confirm-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import { ArrowBigRightDashIcon } from 'lucide-react';

interface NewPollConfirmDialogProps {
handleProceedNewPoll: () => void;
}

const NewPollConfirmDialog = ({
handleProceedNewPoll,
}: NewPollConfirmDialogProps) => {
return (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button className='mt-8 flex w-32 self-end bg-gray-600'>
Next Poll
<ArrowBigRightDashIcon className='ml-1 w-8' />
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Confirmation</AlertDialogTitle>
<AlertDialogDescription>
Creating next new poll will discard current poll records. This
webapp will not keep the poll records and this action cannot be
undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={handleProceedNewPoll}>
Continue
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

export default NewPollConfirmDialog;
4 changes: 2 additions & 2 deletions components/poll-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useCallback, useRef, useState } from 'react';
import { useToast } from '@/components/ui/use-toast';

import { AuthForm } from './auth-form';
import PollSection from './poll-section';
import PollCardGroup from './poll-cardgroup';

const PollApp = () => {
const [isAuth, setIsAuth] = useState(false);
Expand Down Expand Up @@ -32,7 +32,7 @@ const PollApp = () => {
{!isAuth ? (
<AuthForm onSubmit={handleAuth} />
) : (
<PollSection currentPassphrase={currentPassphrase} />
<PollCardGroup currentPassphrase={currentPassphrase} />
)}
</div>
);
Expand Down
188 changes: 37 additions & 151 deletions components/poll-section.tsx → components/poll-cardgroup.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import UrlInput from './url-input';
import { useCallback, useEffect, useRef, useState } from 'react';
import { vidParser } from '@/lib/vid-parser';
import { LiveMetadata, MessageData, PollUserData } from '@/types/liveChat';
import { useLiveChat } from '@/hooks/use-livechat';
import { useToast } from './ui/use-toast';
import { Label } from './ui/label';
import { useToast } from '@/components/ui/use-toast';
import { Label } from '@/components/ui/label';
import { Card, CardContent, CardHeader, CardTitle } from './ui/card';
import { Input } from './ui/input';
import { Button } from './ui/button';
import { ArrowBigRightDashIcon, PlayIcon, StopCircleIcon } from 'lucide-react';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from '@/components/ui/alert-dialog';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { PlayIcon, StopCircleIcon } from 'lucide-react';
import { Bar } from 'react-chartjs-2';
import {
Chart as ChartJS,
Expand All @@ -30,14 +18,17 @@ import {
Tooltip,
Legend,
} from 'chart.js';
import { randomRGBAColor } from '@/lib/random-rgba-color';
import LiveStreamMetadataCard from './livestream-metadata-card';
import Spinner from './spinner';
import LiveStreamMetadataCard from '@/components/livestream-metadata-card';
import Spinner from '@/components/spinner';
import { defaultBaseInterval, isNumeric } from '@/lib/utils';
import dayjs from 'dayjs';
import { Checkbox } from './ui/checkbox';
import { Checkbox } from '@/components/ui/checkbox';
import { useChartConfig } from '@/hooks/use-chart-config';
import NewPollConfirmDialog from '@/components/new-poll-confirm-dialog';
import PollSummarySubCard from '@/components/poll-summary-subcard';
import UrlInput from '@/components/url-input';

interface UrlInputSectionProps {
interface PollCardGroupProps {
currentPassphrase: string;
}

Expand All @@ -52,7 +43,7 @@ ChartJS.register(
Legend
);

const PollSection = ({ currentPassphrase }: UrlInputSectionProps) => {
const PollCardGroup = ({ currentPassphrase }: PollCardGroupProps) => {
const { toast } = useToast();
const [isLoading, setIsLoading] = useState(false);
const [isReady, setIsReady] = useState(false);
Expand Down Expand Up @@ -83,7 +74,6 @@ const PollSection = ({ currentPassphrase }: UrlInputSectionProps) => {
const [pollData, setPollData] = useState<PollUserData>({});
const [pollStartDate, setPollStartDate] = useState<dayjs.Dayjs>();
const [pollSummary, setPollSummary] = useState<number[]>([]);
const [pollSummaryTop, setPollSummaryTop] = useState<number>(0);
const [allowUpdatePollOptions, setAllowUpdatePollOptions] = useState(true);

const { fetchLiveChatMessage, fetchLiveStreamingDetails, extractMessage } =
Expand Down Expand Up @@ -230,7 +220,6 @@ const PollSection = ({ currentPassphrase }: UrlInputSectionProps) => {
const sortChartResult = useCallback(() => {
const data = new Array(numOfOptions).fill(0);

// MOCKData: {'Sawa': 5, 'userA': 5, 'Sam': 1, 'userB': 5, 'userC': 2}
Object.values(pollData).forEach((v) => {
if (v > 0 && v <= numOfOptions) {
data[v - 1]++;
Expand All @@ -249,9 +238,7 @@ const PollSection = ({ currentPassphrase }: UrlInputSectionProps) => {
});

const pollSummary = arrayOfObj.map((it) => it.data);
const topIndex = pollSummary.indexOf(Math.max(...pollSummary));
setPollSummary(pollSummary);
setPollSummaryTop(topIndex);
const sortedArrayOfObj = arrayOfObj.sort((a, b) =>
a.data === b.data ? 0 : a.data > b.data ? -1 : 1
);
Expand All @@ -268,7 +255,7 @@ const PollSection = ({ currentPassphrase }: UrlInputSectionProps) => {
newArrayLabel.push(`${d.label}`);
}
newArrayData.push(d.data);
newBarColor.push(d.backgroundColor); // seems buggy here
newBarColor.push(d.backgroundColor);
newBorderColor.push(d.borderColor);
});

Expand All @@ -281,76 +268,22 @@ const PollSection = ({ currentPassphrase }: UrlInputSectionProps) => {
}
}, [barColor?.bar, barColor?.border, numOfOptions, pollData]);

const chartInitData = useMemo(() => {
const labels = Array.from(Array(numOfOptions).keys()).map(
(i) => `${i + 1}`
);
const color = randomRGBAColor(numOfOptions);
setBarColor(color);

return {
labels,
datasets: [
{
label: 'Poll',
data: [],
backgroundColor: color.bar,
borderColor: color.border,
maxBarThickness: 24,
},
],
};
}, [numOfOptions]);

const chartOptions = useMemo(() => {
return {
indexAxis: 'y' as const,
elements: {
bar: {
borderWidth: 2,
},
},
responsive: true,
plugins: {
legend: {
display: false,
},
title: {
display: false,
},
},
scales: {
y: {
title: {
display: true,
text: 'Option🎫',
color: '#dddddd',
},
ticks: {
color: '#dddddd',
},
grid: {
color: '#81112a',
lineWidth: 0.5,
},
},
x: {
title: {
display: true,
color: '#dddddd',
text: 'Count',
},
ticks: {
color: '#dddddd',
stepSize: 1,
},
grid: {
color: '#cd1b42',
lineWidth: 1,
},
},
},
};
const { chartOptions, chartInitData, chartColor } =
useChartConfig(numOfOptions);

useEffect(() => {
// memories chartColor scheme
setBarColor(chartColor);
}, [chartColor]);

const handleProceedNewPoll = useCallback(() => {
setPollStatus('prepare');
setPollData({});
setNumOfOptions(0);
setPollSummary([]);
if (inputRef.current) {
inputRef.current.value = '';
}
}, []);

return (
Expand Down Expand Up @@ -471,23 +404,8 @@ const PollSection = ({ currentPassphrase }: UrlInputSectionProps) => {
redraw
/>
{pollStatus === 'stop' && (
<div className='mt-8'>
<CardTitle className='font-extrabold uppercase text-primary'>
📊 Poll Summary
</CardTitle>
<div className='mt-8 flex flex-col rounded-md border-2 border-secondary p-8'>
{pollSummary.map((value, index) => {
return (
<div key={index + 1}>
{index + 1}: {value ?? 0}{' '}
{pollSummaryTop === index && '👑'}
</div>
);
})}
</div>
</div>
<PollSummarySubCard pollSummary={pollSummary} />
)}

{pollStatus === 'start' && (
<Button
className='mt-8 flex w-32 self-end'
Expand All @@ -502,41 +420,9 @@ const PollSection = ({ currentPassphrase }: UrlInputSectionProps) => {
</Button>
)}
{pollStatus === 'stop' && (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button className='mt-8 flex w-32 self-end bg-gray-600'>
Next Poll
<ArrowBigRightDashIcon className='ml-1 w-8' />
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Confirmation</AlertDialogTitle>
<AlertDialogDescription>
Creating next new poll will discard current poll
records. This webapp will not keep the poll records
and this action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={() => {
setPollStatus('prepare');
setPollData({});
setNumOfOptions(0);
setPollSummary([]);
setPollSummaryTop(0);
if (inputRef.current) {
inputRef.current.value = '';
}
}}
>
Continue
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<NewPollConfirmDialog
handleProceedNewPoll={handleProceedNewPoll}
/>
)}
</CardContent>
</Card>
Expand All @@ -547,4 +433,4 @@ const PollSection = ({ currentPassphrase }: UrlInputSectionProps) => {
);
};

export default PollSection;
export default PollCardGroup;
31 changes: 31 additions & 0 deletions components/poll-summary-subcard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { CardTitle } from '@/components/ui/card';
import { useMemo, useState } from 'react';

interface PollSummarySubCardProps {
pollSummary: number[];
}

const PollSummarySubCard = ({ pollSummary }: PollSummarySubCardProps) => {
const pollSummaryTop = useMemo(() => {
return pollSummary.indexOf(Math.max(...pollSummary));
}, [pollSummary]);

return (
<div className='mt-8'>
<CardTitle className='font-extrabold uppercase text-primary'>
📊 Poll Summary
</CardTitle>
<div className='mt-8 flex flex-col rounded-md border-2 border-secondary p-8'>
{pollSummary.map((value, index) => {
return (
<div key={index + 1}>
{index + 1}: {value ?? 0} {pollSummaryTop === index && '👑'}
</div>
);
})}
</div>
</div>
);
};

export default PollSummarySubCard;
Loading

0 comments on commit e7888a0

Please sign in to comment.