Commit c6293a41 authored by Max Alekseenko's avatar Max Alekseenko

split the rating component into multiple files

parent 273f5dca
......@@ -10,7 +10,7 @@ import IconSvg from 'ui/shared/IconSvg';
import AppSecurityReport from './AppSecurityReport';
import MarketplaceAppCardLink from './MarketplaceAppCardLink';
import MarketplaceAppIntegrationIcon from './MarketplaceAppIntegrationIcon';
import Rating from './Rating';
import Rating from './Rating/Rating';
interface Props extends MarketplaceAppWithSecurityReport {
onInfoClick: (id: string) => void;
......
......@@ -15,7 +15,7 @@ import IconSvg from 'ui/shared/IconSvg';
import AppSecurityReport from './AppSecurityReport';
import MarketplaceAppModalLink from './MarketplaceAppModalLink';
import Rating from './Rating';
import Rating from './Rating/Rating';
type Props = {
onClose: () => void;
......
import { Text, Flex, Spinner } from '@chakra-ui/react';
import React from 'react';
import IconSvg from 'ui/shared/IconSvg';
import Stars from './Stars';
const ratingDescriptions = [ 'Terrible', 'Poor', 'Average', 'Very good', 'Outstanding' ];
type Props = {
appId: string;
recordId?: string;
isRatedByUser?: boolean;
rate: (appId: string, recordId: string | undefined, rating: number) => void;
isSending?: boolean;
};
const PopoverContent = ({ appId, recordId, isRatedByUser, rate, isSending }: Props) => {
const [ hovered, setHovered ] = React.useState(-1);
const handleMouseOverFactory = React.useCallback((index: number) => () => {
setHovered(index);
}, []);
const handleMouseOut = React.useCallback(() => {
setHovered(-1);
}, []);
const handleRateFactory = React.useCallback((index: number) => () => {
rate(appId, recordId, index + 1);
}, [ appId, recordId, rate ]);
if (isRatedByUser) {
return (
<Flex alignItems="center">
<IconSvg name="check_circle" color="green.500" boxSize={ 8 }/>
<Text fontSize="md" ml={ 3 }>App is already rated</Text>
</Flex>
);
}
if (isSending) {
return (
<Flex alignItems="center">
<Spinner size="md"/>
<Text fontSize="md" ml={ 3 }>Sending your feedback</Text>
</Flex>
);
}
return (
<>
<Text fontWeight="500" fontSize="xs" lineHeight="30px" variant="secondary">
How was your experience?
</Text>
<Flex alignItems="center" h="32px">
<Stars
filledIndex={ hovered }
onMouseOverFactory={ handleMouseOverFactory }
onMouseOut={ handleMouseOut }
onClickFactory={ handleRateFactory }
/>
{ hovered >= 0 && (
<Text fontSize="md" ml={ 2 }>
{ ratingDescriptions[ hovered ] }
</Text>
) }
</Flex>
</>
);
};
export default PopoverContent;
import {
Text, Popover, PopoverTrigger, PopoverBody, PopoverContent, useDisclosure,
Button, Flex, Spinner, Skeleton, chakra, useColorModeValue,
Text, Popover, PopoverTrigger, PopoverBody, PopoverContent,
useDisclosure, Button, Skeleton, chakra, useColorModeValue,
} from '@chakra-ui/react';
import React from 'react';
import type { MouseEventHandler } from 'react';
import IconSvg from 'ui/shared/IconSvg';
const ratingDescriptions = [ 'Terrible', 'Poor', 'Average', 'Very good', 'Outstanding' ];
import Content from './PopoverContent';
import Stars from './Stars';
type StarsProps = {
filledIndex: number;
onMouseOverFactory?: (index: number) => MouseEventHandler<HTMLDivElement>;
onMouseOut?: () => void;
onClickFactory?: (index: number) => MouseEventHandler<HTMLDivElement>;
};
const Stars = ({ filledIndex, onMouseOverFactory, onMouseOut, onClickFactory }: StarsProps) => (
<>
{ Array(5).fill(null).map((_, index) => (
<IconSvg
key={ index }
name={ filledIndex >= index ? 'star_filled' : 'star_outline' }
color={ filledIndex >= index ? 'yellow.400' : 'gray.400' }
w={ 6 } // 5 + 1 padding
h={ 5 }
pr={ 1 } // use padding intead of margin so that there are no empty spaces between stars without hover effect
cursor={ onMouseOverFactory ? 'pointer' : 'default' }
onMouseOver={ onMouseOverFactory?.(index) }
onMouseOut={ onMouseOut }
onClick={ onClickFactory?.(index) }
/>
)) }
</>
);
type ContentProps = {
appId: string;
recordId?: string;
isRatedByUser?: boolean;
rate: (appId: string, recordId: string | undefined, rating: number) => void;
isSending?: boolean;
};
const Content = ({ appId, recordId, isRatedByUser, rate, isSending }: ContentProps) => {
const [ hovered, setHovered ] = React.useState(-1);
const handleMouseOverFactory = React.useCallback((index: number) => () => {
setHovered(index);
}, []);
const handleMouseOut = React.useCallback(() => {
setHovered(-1);
}, []);
const handleRateFactory = React.useCallback((index: number) => () => {
rate(appId, recordId, index + 1);
}, [ appId, recordId, rate ]);
if (isRatedByUser) {
return (
<Flex alignItems="center">
<IconSvg name="check_circle" color="green.500" boxSize={ 8 }/>
<Text fontSize="md" ml={ 3 }>App is already rated</Text>
</Flex>
);
}
if (isSending) {
return (
<Flex alignItems="center">
<Spinner size="md"/>
<Text fontSize="md" ml={ 3 }>Sending your feedback</Text>
</Flex>
);
}
return (
<>
<Text fontWeight="500" fontSize="xs" lineHeight="30px" variant="secondary">
How was your experience?
</Text>
<Flex alignItems="center" h="32px">
<Stars
filledIndex={ hovered }
onMouseOverFactory={ handleMouseOverFactory }
onMouseOut={ handleMouseOut }
onClickFactory={ handleRateFactory }
/>
{ hovered >= 0 && (
<Text fontSize="md" ml={ 2 }>
{ ratingDescriptions[ hovered ] }
</Text>
) }
</Flex>
</>
);
};
type RatingProps = {
type Props = {
appId: string;
rating?: number;
recordId?: string;
......@@ -109,7 +20,7 @@ type RatingProps = {
fullView?: boolean;
};
const Rating = ({ appId, rating, recordId, isRatedByUser, rate, isSending, isLoading, fullView }: RatingProps) => {
const Rating = ({ appId, rating, recordId, isRatedByUser, rate, isSending, isLoading, fullView }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure();
const textColor = useColorModeValue('blackAlpha.800', 'whiteAlpha.800');
......
import React from 'react';
import type { MouseEventHandler } from 'react';
import IconSvg from 'ui/shared/IconSvg';
type Props = {
filledIndex: number;
onMouseOverFactory?: (index: number) => MouseEventHandler<HTMLDivElement>;
onMouseOut?: () => void;
onClickFactory?: (index: number) => MouseEventHandler<HTMLDivElement>;
};
const Stars = ({ filledIndex, onMouseOverFactory, onMouseOut, onClickFactory }: Props) => (
<>
{ Array(5).fill(null).map((_, index) => (
<IconSvg
key={ index }
name={ filledIndex >= index ? 'star_filled' : 'star_outline' }
color={ filledIndex >= index ? 'yellow.400' : 'gray.400' }
w={ 6 } // 5 + 1 padding
h={ 5 }
pr={ 1 } // use padding intead of margin so that there are no empty spaces between stars without hover effect
cursor={ onMouseOverFactory ? 'pointer' : 'default' }
onMouseOver={ onMouseOverFactory?.(index) }
onMouseOut={ onMouseOut }
onClick={ onClickFactory?.(index) }
/>
)) }
</>
);
export default Stars;
......@@ -10,7 +10,7 @@ import useApiFetch from 'lib/api/useApiFetch';
import useFetch from 'lib/hooks/useFetch';
import { MARKETPLACE_APP } from 'stubs/marketplace';
import useRatings from './useRatings';
import useRatings from './Rating/useRatings';
import useSecurityReports from './useSecurityReports';
import type { SortValue } from './utils';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment