Skip to content

Commit

Permalink
Merge pull request #9 from alonkeyval/gen-1120-choose-destination-list
Browse files Browse the repository at this point in the history
[GEN-1120] chore: choose destination list
  • Loading branch information
alonkeyval authored Aug 5, 2024
2 parents 3b46524 + d43d439 commit 833e439
Show file tree
Hide file tree
Showing 26 changed files with 701 additions and 129 deletions.
9 changes: 8 additions & 1 deletion frontend/webapp/app/setup/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,14 @@ export default function SetupLayout({
return (
<LayoutContainer>
<HeaderWrapper>
<SetupHeader />
<SetupHeader
onBack={function (): void {
throw new Error('Function not implemented.');
}}
onNext={function (): void {
throw new Error('Function not implemented.');
}}
/>
</HeaderWrapper>
<SideMenuWrapper>
<SideMenu />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import Image from 'next/image';
import theme from '@/styles/theme';
import styled from 'styled-components';
import { Button, Text } from '@/reuseable-components';

const StyledAddDestinationButton = styled(Button)`
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
`;

interface ModalActionComponentProps {
onClick: () => void;
}

export function AddDestinationButton({ onClick }: ModalActionComponentProps) {
return (
<StyledAddDestinationButton variant="secondary" onClick={onClick}>
<Image src="/icons/common/plus.svg" alt="back" width={16} height={16} />
<Text
color={theme.colors.secondary}
size={14}
decoration={'underline'}
family="secondary"
>
ADD DESTINATION
</Text>
</StyledAddDestinationButton>
);
}
2 changes: 2 additions & 0 deletions frontend/webapp/components/destinations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './add-destination-button';
export * from './monitors-tap-list';
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import styled from 'styled-components';
import { Text, Tag } from '@/reuseable-components';
import { MONITORS_OPTIONS } from '@/utils';

interface MonitorButtonsProps {
selectedMonitors: string[];
onMonitorSelect: (monitor: string) => void;
}

const MonitorButtonsContainer = styled.div`
display: flex;
gap: 8px;
margin-left: 12px;
`;

const MonitorsTitle = styled(Text)`
opacity: 0.8;
font-size: 14px;
margin-left: 32px;
`;

const MonitorsTapList: React.FC<MonitorButtonsProps> = ({
selectedMonitors,
onMonitorSelect,
}) => {
return (
<>
<MonitorsTitle>Monitor by:</MonitorsTitle>
<MonitorButtonsContainer>
{MONITORS_OPTIONS.map((monitor) => (
<Tag
id={monitor.id}
isSelected={selectedMonitors.includes(monitor.id)}
onClick={() => onMonitorSelect(monitor.id)}
>
<Text size={12} color="rgba(249, 249, 249, 0.8)">
{monitor.value}
</Text>
</Tag>
))}
</MonitorButtonsContainer>
</>
);
};

export { MonitorsTapList };
1 change: 1 addition & 0 deletions frontend/webapp/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './overview';
export * from './common';
export * from './notification/notification-manager';
export * from './notification/notification-list';
export * from './destinations';
18 changes: 5 additions & 13 deletions frontend/webapp/components/setup/menu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { Text } from '@/reuseable-components';
import { StepProps } from '@/types';
import Image from 'next/image';
import React from 'react';
import styled, { css } from 'styled-components';

interface StepProps {
title: string;
subtitle?: string;
state: 'finish' | 'active' | 'disabled';
stepNumber: number;
}

const Container = styled.div`
display: flex;
flex-direction: column;
Expand All @@ -33,11 +27,10 @@ const Step = styled.div<{ state: 'finish' | 'active' | 'disabled' }>`
`;

const IconWrapper = styled.div<{ state: 'finish' | 'active' | 'disabled' }>`
margin-right: 10px;
border-radius: 32px;
width: 24px;
height: 24px;
border: 1px solid #f9f9f9;
border: 1px solid ${({ theme }) => theme.colors.secondary};
display: flex;
justify-content: center;
align-items: center;
Expand All @@ -61,14 +54,13 @@ const StepContent = styled.div`
`;

const StepTitle = styled(Text)`
font-size: 16px;
font-weight: bold;
font-weight: 500;
`;

const StepSubtitle = styled(Text)``;

const SideMenu: React.FC = () => {
const steps: StepProps[] = [
const SideMenu: React.FC<{ data?: StepProps[] }> = ({ data }) => {
const steps: StepProps[] = data || [
{
title: 'INSTALLATION',
subtitle: 'Success',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useEffect, useState } from 'react';
import { useQuery } from '@apollo/client';
import { DestinationTypeItem } from '@/types';
import { GET_DESTINATION_TYPE } from '@/graphql';
import { Modal, NavigationButtons } from '@/reuseable-components';
import { ConnectDestinationModalBody } from '../connect-destination-modal-body';
import { ChooseDestinationModalBody } from '../choose-destination-modal-body';

interface AddDestinationModalProps {
isModalOpen: boolean;
handleCloseModal: () => void;
}

function ModalActionComponent({
onNext,
onBack,
item,
}: {
onNext: () => void;
onBack: () => void;
item: DestinationTypeItem | undefined;
}) {
return (
<NavigationButtons
buttons={
item
? [
{
label: 'BACK',
iconSrc: '/icons/common/arrow-white.svg',
onClick: onBack,
variant: 'secondary',
},
{
label: 'DONE',
onClick: onNext,
variant: 'primary',
},
]
: []
}
/>
);
}

export function AddDestinationModal({
isModalOpen,
handleCloseModal,
}: AddDestinationModalProps) {
const { data } = useQuery(GET_DESTINATION_TYPE);
const [selectedItem, setSelectedItem] = useState<DestinationTypeItem>();
const [destinationTypeList, setDestinationTypeList] = useState<
DestinationTypeItem[]
>([]);

useEffect(() => {
data && buildDestinationTypeList();
}, [data]);

function buildDestinationTypeList() {
const destinationTypes = data?.destinationTypes?.categories || [];
const destinationTypeList: DestinationTypeItem[] = destinationTypes.reduce(
(acc: DestinationTypeItem[], category: any) => {
const items = category.items.map((item: any) => ({
category: category.name,
displayName: item.displayName,
imageUrl: item.imageUrl,
supportedSignals: item.supportedSignals,
}));
return [...acc, ...items];
},
[]
);
setDestinationTypeList(destinationTypeList);
}
function handleNextStep(item: DestinationTypeItem) {
setSelectedItem(item);
}

function renderModalBody() {
return selectedItem ? (
<ConnectDestinationModalBody destination={selectedItem} />
) : (
<ChooseDestinationModalBody
data={destinationTypeList}
onSelect={handleNextStep}
/>
);
}

return (
<Modal
isOpen={isModalOpen}
actionComponent={
<ModalActionComponent
onNext={() => {}}
onBack={() => setSelectedItem(undefined)}
item={selectedItem}
/>
}
header={{ title: 'Add destination' }}
onClose={handleCloseModal}
>
{renderModalBody()}
</Modal>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import { DropdownOption } from '@/types';
import { MonitorsTapList } from '@/components';
import { Dropdown, Input } from '@/reuseable-components';

interface FilterComponentProps {
selectedTag: DropdownOption | undefined;
onTagSelect: (option: DropdownOption) => void;
onSearch: (value: string) => void;
selectedMonitors: string[];
onMonitorSelect: (monitor: string) => void;
}

const InputAndDropdownContainer = styled.div`
display: flex;
gap: 12px;
width: 438px;
`;

const FilterContainer = styled.div`
display: flex;
align-items: center;
padding: 24px 0;
`;

const DROPDOWN_OPTIONS = [
{ value: 'All', id: 'all' },
{ value: 'Managed', id: 'managed' },
{ value: 'Self-hosted', id: 'self hosted' },
];

const DestinationFilterComponent: React.FC<FilterComponentProps> = ({
selectedTag,
onTagSelect,
onSearch,
selectedMonitors,
onMonitorSelect,
}) => {
const [searchTerm, setSearchTerm] = useState('');

const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setSearchTerm(value);
onSearch(value);
};

return (
<FilterContainer>
<InputAndDropdownContainer>
<Input
placeholder="Search..."
icon="/icons/common/search.svg"
value={searchTerm}
onChange={handleSearchChange}
/>
<Dropdown
options={DROPDOWN_OPTIONS}
selectedOption={selectedTag}
onSelect={onTagSelect}
/>
</InputAndDropdownContainer>
<MonitorsTapList
selectedMonitors={selectedMonitors}
onMonitorSelect={onMonitorSelect}
/>
</FilterContainer>
);
};

export { DestinationFilterComponent };
Loading

0 comments on commit 833e439

Please sign in to comment.