Add content to the Discussion Panel

This commit is contained in:
Charles Bochet 2022-12-06 11:37:43 +01:00
parent 33c30e0770
commit fd56c69970
22 changed files with 534 additions and 16 deletions

View File

@ -47,9 +47,6 @@
"react-refresh": "0.14.0" "react-refresh": "0.14.0"
}, },
"jest": { "jest": {
"coveragePathIgnorePatterns": [
"src/stories"
]
}, },
"browserslist": { "browserslist": {
"production": [ "production": [

View File

@ -1,12 +1,100 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import Composer from './composer/Composer';
import Booking, { BookingEvent } from './events/Booking';
import Message, { MessageEvent } from './events/Message';
import Note, { NoteEvent } from './events/Note';
export type Event = BookingEvent | MessageEvent | NoteEvent;
const StyledPanel = styled.div` const StyledPanel = styled.div`
display: flex; display: flex;
flex-grow: 1; flex-grow: 1;
flex-direction: column;
`;
const EventsContainer = styled.div`
display: flex;
flex-grow: 1;
flex-direction: column;
padding: 32px;
`;
const StyledToday = styled.div`
font-size: 12px;
color: #2e3138;
border-bottom: 1px solid #eaecee;
margin-top: 32px;
padding-bottom: 8px;
margin-bottom: 8px;
`;
const ComposerContainer = styled.div`
display: flex;
padding: 32px;
flex-direction: column;
flex-grow: 1;
`; `;
function DiscussionPanel() { function DiscussionPanel() {
return <StyledPanel></StyledPanel>; return (
<StyledPanel>
<EventsContainer>
<Booking
booking={{
id: 1,
time: 'Wed, Sep 10, 2022',
user: 'Georges',
nights: 4,
guests: 5,
price: '756.90$',
listing: 'Rochefort Montagne',
dateRange: 'Mon, Sep 30 - Fri, Oct 2',
}}
/>
<StyledToday>Today</StyledToday>
<Message
message={{
id: 1,
time: '2 hours ago',
user: 'Georges Alain',
channel: 'sms',
message:
'Im looking for my order but couldnt find it. Could you help me find it. I dont know where to look for.',
}}
/>
<Message
message={{
id: 2,
time: 'just now',
user: 'Support',
channel: 'sms',
message: 'Hello Im here bla bla bla',
agent: 'Leslie A',
}}
/>
<Note
note={{
id: 1,
time: 'just now',
agent: 'LeslieA',
message: 'Hello Im here bla bla bla',
}}
/>
<Message
message={{
id: 3,
time: 'just now',
user: 'Georges Alain',
channel: 'sms',
message: 'Thank you !',
}}
/>
</EventsContainer>
<ComposerContainer>
<Composer />
</ComposerContainer>
</StyledPanel>
);
} }
export default DiscussionPanel; export default DiscussionPanel;

View File

@ -0,0 +1,8 @@
import DiscussionPanel from '../DiscussionPanel';
export default {
title: 'DiscussionPanel',
component: DiscussionPanel,
};
export const DiscussionPanelDefault = () => <DiscussionPanel />;

View File

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import { DiscussionPanelDefault } from '../__stories__/DiscussionPanel.stories';
it('Checks the discussion panel render', () => {
const { getAllByText } = render(<DiscussionPanelDefault />);
const text = getAllByText('Rochefort Montagne');
expect(text).toBeDefined();
});

View File

@ -1,7 +1,57 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import ComposerSwitch from './ComposerSwitch';
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
border: 2px solid #000000;
border-radius: 12px;
`;
const StyledInputContainer = styled.div`
display: flex;
padding: 8px;
justify-content: center;
& > textarea {
width: 95%;
border: none;
outline: none;
font-family: 'Source Sans Pro';
&::placeholder {
font-family: 'Source Sans Pro';
}
}
`;
const ActionContainer = styled.div`
display: flex;
padding: 16px;
justify-content: flex-end;
`;
const PrimaryButton = styled.button`
background: black;
font-weight: bold;
color: white;
padding: 16px 24px;
border: 0;
border-radius: 12px;
cursor: pointer;
`;
function Composer() { function Composer() {
return; return (
<StyledContainer>
<ComposerSwitch />
<StyledInputContainer>
<textarea rows={5} placeholder="Type to chat..."></textarea>
</StyledInputContainer>
<ActionContainer>
<PrimaryButton>Reply by SMS</PrimaryButton>
</ActionContainer>
</StyledContainer>
);
} }
export default Composer; export default Composer;

View File

@ -1,7 +1,49 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
const StyledContainer = styled.div`
display: flex;
flex-direction: row;
border-bottom: 2px solid #eaecee;
padding: 0px 12px;
`;
const SwitchTab = styled.button`
display: flex;
border-bottom: 2px solid #eaecee;
margin-bottom: -2px;
padding: 12px;
cursor: pointer;
color: #2e3138;
background: inherit;
border: 0;
&:hover {
border-bottom: 2px solid #2e3138;
}
`;
const SwitchTabActive = styled.button`
display: flex;
border: 0;
border-bottom: 2px solid black;
margin-bottom: -2px;
padding: 12px;
cursor: pointer;
color: black;
font-weight: bold;
background: inherit;
`;
function ComposerSwitch() { function ComposerSwitch() {
return; return (
<StyledContainer>
<SwitchTabActive>Reply</SwitchTabActive>
<SwitchTab>Call</SwitchTab>
<SwitchTab>Note</SwitchTab>
<SwitchTab>Transfer</SwitchTab>
<SwitchTab>Help</SwitchTab>
</StyledContainer>
);
} }
export default ComposerSwitch; export default ComposerSwitch;

View File

@ -0,0 +1,8 @@
import Composer from '../Composer';
export default {
title: 'Composer',
component: Composer,
};
export const ComposerDefault = () => <Composer />;

View File

@ -0,0 +1,8 @@
import ComposerSwitch from '../ComposerSwitch';
export default {
title: 'Composer',
component: ComposerSwitch,
};
export const ComposerSwithDefault = () => <ComposerSwitch />;

View File

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import { ComposerDefault } from '../__stories__/Composer.stories';
it('Checks the composer render', () => {
const { getAllByRole } = render(<ComposerDefault />);
const button = getAllByRole('button');
expect(button[0]).toHaveTextContent('Reply');
});

View File

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import { ComposerSwithDefault } from '../__stories__/ComposerSwitch.stories';
it('Checks the composer switch render', () => {
const { getAllByRole } = render(<ComposerSwithDefault />);
const button = getAllByRole('button');
expect(button[0]).toHaveTextContent('Reply');
});

View File

@ -1,7 +1,80 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
function Booking() { export type BookingEvent = {
return; id: number;
user: string;
time: string;
listing: string;
nights: number;
guests: number;
price: string;
dateRange: string;
};
type OwnProps = {
booking: BookingEvent;
};
const StyledBooking = styled.div`
display: flex;
flex-direction: column;
`;
const StyledLabel = styled.div`
font-size: 12px;
color: #2e3138;
margin-bottom: 8px;
`;
const StyledContainer = styled.div`
display: flex;
padding: 16px;
flex-direction: row;
border: 1px solid #000000;
border-radius: 12px;
`;
const StyledPicture = styled.div`
background: #2e3138;
width: 50px;
height: 42px;
margin-right: 16px;
`;
const StyledContent = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
`;
const StyledListing = styled.div`
font-size: 16px;
font-weight: bold;
`;
const StyledDetails = styled.div`
font-size: 12px;
color: #2e3138;
`;
function Booking({ booking }: OwnProps) {
return (
<StyledBooking>
<StyledLabel>
{booking.time} · {booking.user} booked a trip
</StyledLabel>
<StyledContainer>
<StyledPicture />
<StyledContent>
<StyledListing>{booking.listing}</StyledListing>
<StyledDetails>
{booking.dateRange} · {booking.nights} nights · {booking.guests}{' '}
guests · {booking.price}
</StyledDetails>
</StyledContent>
</StyledContainer>
</StyledBooking>
);
} }
export default Booking; export default Booking;

View File

@ -1,7 +1,90 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
function Message() { export type MessageEvent = {
return; id: number;
user: string;
time: string;
channel: string;
message: string;
agent?: string;
};
type OwnProps = {
message: MessageEvent;
};
const StyledMessage = styled.div`
display: flex;
margin-top: 12px;
margin-bottom: 20px;
`;
const StyledAvatar = styled.div`
display: flex;
width: 40px;
height: 40px;
border-radius: 40px;
background: black;
font-size: 20px;
color: white;
align-items: center;
justify-content: center;
font-weight: bold;
margin-right: 16px;
flex-shrink: 0;
`;
const StyledContent = styled.div``;
const StyledTitle = styled.div`
display: flex;
align-items: center;
`;
const StyledUser = styled.div`
font-size: 16px;
color: black;
font-weight: bold;
`;
const StyledTime = styled.div`
margin-left: 8px;
font-size: 12px;
color: #2e3138;
`;
const StyledAgent = styled.div`
text-decoration: underline;
margin-left: 4px;
font-size: 12px;
color: #2e3138;
`;
const StyledDetails = styled.div`
margin-top: 8px;
`;
function Message({ message }: OwnProps) {
return (
<StyledMessage>
<StyledAvatar>
{message.user
.split(' ')
.map((n) => n[0])
.join('')}
</StyledAvatar>
<StyledContent>
<StyledTitle>
<StyledUser>{message.user}</StyledUser>
<StyledTime>
{message.time} ({message.channel})
</StyledTime>
{message.agent && <StyledAgent>by {message.agent}</StyledAgent>}
</StyledTitle>
<StyledDetails>{message.message}</StyledDetails>
</StyledContent>
</StyledMessage>
);
} }
export default Message; export default Message;

View File

@ -1,7 +1,52 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
function Note() { export type NoteEvent = {
return; id: number;
time: string;
message: string;
agent: string;
};
type OwnProps = {
note: NoteEvent;
};
const StyledNote = styled.div`
display: flex;
background: #f8f9fa;
border-left: 4px solid black;
padding: 8px 20px;
flex-direction: column;
margin-top: 12px;
margin-bottom: 20px;
`;
const StyledLabel = styled.div`
font-size: 12px;
color: #2e3138;
margin-bottom: 8px;
display: flex;
flex-direction: row;
`;
const StyledAgent = styled.div`
text-decoration: underline;
margin-left: 4px;
font-size: 12px;
color: #2e3138;
`;
const StyledMessage = styled.div``;
function Note({ note }: OwnProps) {
return (
<StyledNote>
<StyledLabel>
Internal Note {note.time} <StyledAgent>by {note.agent}</StyledAgent>
</StyledLabel>
<StyledMessage>{note.message}</StyledMessage>
</StyledNote>
);
} }
export default Note; export default Note;

View File

@ -0,0 +1,21 @@
import Booking from '../Booking';
export default {
title: 'DiscussionPanel',
component: Booking,
};
export const BookingDefault = () => (
<Booking
booking={{
id: 1,
time: 'Wed, Sep 10, 2022',
user: 'Georges',
nights: 4,
guests: 5,
price: '756.90$',
listing: 'Rochefort Montagne',
dateRange: 'Mon, Sep 30 - Fri, Oct 2',
}}
/>
);

View File

@ -0,0 +1,19 @@
import Message from '../Message';
export default {
title: 'DiscussionPanel',
component: Message,
};
export const MessageDefault = () => (
<Message
message={{
id: 1,
time: '2 hours ago',
user: 'Georges Alain',
channel: 'sms',
message:
'Im looking for my order but couldnt find it. Could you help me find it. I dont know where to look for.',
}}
/>
);

View File

@ -0,0 +1,17 @@
import Note from '../Note';
export default {
title: 'DiscussionPanel',
component: Note,
};
export const NoteDefault = () => (
<Note
note={{
id: 1,
time: 'just now',
agent: 'LeslieA',
message: 'Hello Im here bla bla bla',
}}
/>
);

View File

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import { BookingDefault } from '../__stories__/Booking.stories';
it('Checks the booking event render', () => {
const { getAllByText } = render(<BookingDefault />);
const text = getAllByText('Rochefort Montagne');
expect(text).toBeDefined();
});

View File

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import { MessageDefault } from '../__stories__/Message.stories';
it('Checks the booking event render', () => {
const { getAllByText } = render(<MessageDefault />);
const text = getAllByText('Georges Alain');
expect(text).toBeDefined();
});

View File

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import { NoteDefault } from '../__stories__/Note.stories';
it('Checks the booking event render', () => {
const { getAllByText } = render(<NoteDefault />);
const text = getAllByText('Hello Im here bla bla bla');
expect(text).toBeDefined();
});

View File

@ -1,7 +1,7 @@
import ListPanel from '../ListPanel'; import ListPanel from '../ListPanel';
export default { export default {
title: 'Inbox', title: 'ListPanel',
component: ListPanel, component: ListPanel,
}; };

View File

@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
import ListPanelHeader from '../ListPanelHeader'; import ListPanelHeader from '../ListPanelHeader';
export default { export default {
title: 'Inbox', title: 'ListPanel',
component: ListPanelHeader, component: ListPanelHeader,
}; };

View File

@ -1,8 +1,7 @@
import { MemoryRouter } from 'react-router-dom';
import ListPanelItem from '../ListPanelItem'; import ListPanelItem from '../ListPanelItem';
export default { export default {
title: 'Inbox', title: 'ListPanel',
component: ListPanelItem, component: ListPanelItem,
}; };