diff --git a/src/components/Message/Message.tsx b/src/components/Message/Message.tsx
index f206922..8f3ebc2 100644
--- a/src/components/Message/Message.tsx
+++ b/src/components/Message/Message.tsx
@@ -2,8 +2,10 @@ import { Suspense } from 'react';
import Linkify from 'react-linkify';
import Attachment from '../Attachment/Attachment';
+import Poll from '../Poll/Poll';
import * as S from './style';
import { IndexedMessage } from '../../types';
+import { parsePollMessage } from '../../utils/poll-parser';
function Link(
decoratedHref: string,
@@ -32,6 +34,22 @@ function Message({
}: IMessage) {
const isSystem = !message.author;
const dateTime = message.date.toISOString().slice(0, 19).replace('T', ' ');
+ const pollData = parsePollMessage(message.message);
+ let messageComponent = (
+
+ {message.message}
+
+ );
+
+ if (message.attachment) {
+ messageComponent = (
+
+
+
+ );
+ } else if (pollData !== null) {
+ messageComponent = ;
+ }
return (
{message.author}
)}
- {message.attachment ? (
-
-
-
- ) : (
-
- {message.message}
-
- )}
+ {messageComponent}
{!isSystem && (
diff --git a/src/components/Poll/Poll.tsx b/src/components/Poll/Poll.tsx
new file mode 100644
index 0000000..b7a6232
--- /dev/null
+++ b/src/components/Poll/Poll.tsx
@@ -0,0 +1,27 @@
+import { PollStructure } from '../../types';
+import * as S from './style';
+
+interface IPoll {
+ pollData: PollStructure;
+}
+
+function Poll({ pollData }: IPoll) {
+ return (
+
+ {pollData.title}
+ {pollData.options.map(option => {
+ return (
+
+ {option.text}
+
+
+ {option.votes}
+
+
+ );
+ })}
+
+ );
+}
+
+export default Poll;
diff --git a/src/components/Poll/style.ts b/src/components/Poll/style.ts
new file mode 100644
index 0000000..dd098aa
--- /dev/null
+++ b/src/components/Poll/style.ts
@@ -0,0 +1,62 @@
+import styled from 'styled-components';
+import {
+ activeUserDarkBackgroundColor,
+ viewerDarkBackgroundColor,
+ whatsappThemeColor,
+} from '../../utils/colors';
+
+const Poll = styled.div`
+ display: flex;
+ flex-direction: column;
+ gap: 0.6rem;
+`;
+
+const Title = styled.div`
+ font-weight: bolder;
+`;
+
+const Option = styled.div`
+ display: flex;
+ flex-direction: column;
+ gap: 0.2rem;
+`;
+
+const Flex = styled.div`
+ display: flex;
+ gap: 0.5rem;
+ align-items: center;
+ font-size: 0.8rem;
+`;
+
+const Progress = styled.progress`
+ display: block;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
+ width: 100%;
+ max-width: 500px;
+ height: 10px;
+ appearance: none;
+ border-radius: 99px;
+ padding: 1px;
+
+ &::-webkit-progress-bar {
+ background-color: white;
+ border-radius: 99px;
+ }
+
+ &::-webkit-progress-value {
+ background-color: ${whatsappThemeColor};
+ border-radius: 99px;
+ }
+
+ @media (prefers-color-scheme: dark) {
+ &::-webkit-progress-bar {
+ background-color: color-mix(
+ in srgb,
+ ${activeUserDarkBackgroundColor},
+ ${viewerDarkBackgroundColor}
+ );
+ }
+ }
+`;
+
+export { Poll, Title, Option, Flex, Progress };
diff --git a/src/types.ts b/src/types.ts
index 79343c5..6dc4ec8 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -19,4 +19,23 @@ interface DateBounds {
end: Date;
}
-export type { FilterMode, ExtractedFile, IndexedMessage, ILimits, DateBounds };
+interface PollOption {
+ text: string;
+ votes: number;
+}
+
+interface PollStructure {
+ title: string;
+ options: PollOption[];
+ maxVotes: number;
+}
+
+export type {
+ FilterMode,
+ ExtractedFile,
+ IndexedMessage,
+ ILimits,
+ DateBounds,
+ PollOption,
+ PollStructure,
+};
diff --git a/src/utils/poll-parser.ts b/src/utils/poll-parser.ts
new file mode 100644
index 0000000..bf5ca00
--- /dev/null
+++ b/src/utils/poll-parser.ts
@@ -0,0 +1,31 @@
+import { PollOption, PollStructure } from '../types';
+
+function parsePollMessage(message: string): PollStructure | null {
+ const lines = message
+ .trim()
+ .split('\n')
+ .map(line => line.trim());
+
+ if (!lines[0].includes('POLL:') || !lines[2]?.includes('OPTION:'))
+ return null;
+
+ const optionRegex = /OPTION: (?.+) \((?\d+).*\)/;
+
+ const options = lines.slice(2).reduce((acc, line) => {
+ const match = optionRegex.exec(line);
+
+ if (!match?.groups) return acc;
+
+ const { text, votes } = match.groups;
+
+ return acc.concat({ text, votes: Number(votes) });
+ }, []);
+
+ return {
+ title: lines[1],
+ options,
+ maxVotes: Math.max(...options.map(o => o.votes)),
+ };
+}
+
+export { parsePollMessage };