Skip to content
This repository was archived by the owner on May 4, 2023. It is now read-only.

Commit 44f1423

Browse files
feat: initial static result pages
1 parent b299d0f commit 44f1423

24 files changed

+1269
-112
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import {
2+
Box,
3+
Text,
4+
Flex,
5+
TableContainer,
6+
Table,
7+
Tr,
8+
Tbody,
9+
Td as ChakraTd,
10+
TableCellProps,
11+
} from '@chakra-ui/react';
12+
import {
13+
LockIcon,
14+
Avatar,
15+
UsersIcon,
16+
CodeIcon,
17+
} from '@codiga/codiga-components';
18+
import { AssistantCookbook } from 'renderer/types/assistantTypes';
19+
import { getAvatarUrl } from 'renderer/utils/userUtils';
20+
import FavoriteCookbook from 'renderer/components/Favorite/FavoriteCookbook';
21+
22+
const Td = (props: TableCellProps) => (
23+
<ChakraTd
24+
{...props}
25+
p="space_16"
26+
pr="space_80"
27+
_first={{ pl: 'space_16' }}
28+
_last={{ pr: 'space_56' }}
29+
/>
30+
);
31+
32+
type CookbookTableProps = {
33+
cookbooks: AssistantCookbook[];
34+
};
35+
36+
export default function CookbookTable({ cookbooks }: CookbookTableProps) {
37+
return (
38+
<Box w="full" overflow="auto">
39+
<TableContainer>
40+
<Table variant="simple">
41+
<Tbody>
42+
{cookbooks.map((cookbook) => {
43+
return (
44+
<Tr
45+
key={cookbook.id}
46+
p="space_16"
47+
border="1px"
48+
borderColor="neutral.50"
49+
bg="neutral.0"
50+
_dark={{ bg: 'neutral.100', borderColor: 'base.onyx' }}
51+
_hover={{
52+
bg: 'neutral.25',
53+
_dark: { bg: 'base.onyx' },
54+
}}
55+
>
56+
<Td>
57+
<Flex alignItems="center" gap="space_8">
58+
<Text size="sm" noOfLines={1}>
59+
{cookbook.name}
60+
</Text>
61+
{!cookbook.groups && (
62+
<FavoriteCookbook
63+
isSubscribed={!!cookbook.isSubscribed}
64+
cookbookId={cookbook.id}
65+
/>
66+
)}
67+
</Flex>
68+
</Td>
69+
{cookbook.groups && cookbook.groups.length > 0 && (
70+
<Td>
71+
<Flex alignItems="center" gap="space_8">
72+
<UsersIcon />
73+
<Text size="xs" noOfLines={1}>
74+
{cookbook?.groups[0]?.name}
75+
</Text>
76+
</Flex>
77+
</Td>
78+
)}
79+
<Td>
80+
<Flex alignItems="center" gap="space_8">
81+
<CodeIcon />
82+
<Text size="xs" noOfLines={1}>
83+
{cookbook?.recipesCount}
84+
</Text>
85+
</Flex>
86+
</Td>
87+
88+
{/* FIXME - LANGUAGES */}
89+
90+
<Td>
91+
<Flex alignItems="center" gap="space_8">
92+
<Avatar
93+
size="xs"
94+
name={cookbook.owner?.displayName || 'Anonymous'}
95+
src={getAvatarUrl({ id: cookbook.owner?.id })}
96+
/>
97+
<Text size="xs" noOfLines={1}>
98+
{cookbook.owner?.displayName || 'Anonymous'}
99+
</Text>
100+
</Flex>
101+
</Td>
102+
<Td>
103+
<Flex alignItems="center" gap="space_8">
104+
<LockIcon open={!!cookbook.isPublic} />
105+
<Text size="xs" noOfLines={1}>
106+
{cookbook.isPublic ? 'Public' : 'Private'}
107+
</Text>
108+
</Flex>
109+
</Td>
110+
<Td>
111+
<Flex alignItems="center" gap="space_8">
112+
<Text size="xs" noOfLines={1}>
113+
{new Date(cookbook.creationTimestampMs!).toDateString()}
114+
</Text>
115+
</Flex>
116+
</Td>
117+
</Tr>
118+
);
119+
})}
120+
</Tbody>
121+
</Table>
122+
</TableContainer>
123+
</Box>
124+
);
125+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Link } from '@chakra-ui/react';
2+
import { EmptyState } from '@codiga/codiga-components';
3+
import { APP_URL } from 'renderer/lib/config';
4+
5+
export default function CookbookTableEmpty() {
6+
return (
7+
<EmptyState
8+
title="No cookbooks found"
9+
description="You don't have any cookbooks. Consider creating one now."
10+
illustration="empty"
11+
py="space_64"
12+
>
13+
<Link
14+
isExternal
15+
href={`${APP_URL}/assistant/cookbook/create`}
16+
variant="primary"
17+
size="sm"
18+
>
19+
Create Cookbook
20+
</Link>
21+
</EmptyState>
22+
);
23+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Link } from '@chakra-ui/react';
2+
import { EmptyState } from '@codiga/codiga-components';
3+
import { APP_URL } from 'renderer/lib/config';
4+
5+
export default function CookbookTableError() {
6+
return (
7+
<EmptyState
8+
title="An error occurred"
9+
description="Please close the app and try again. Contact our support, if the issue persists."
10+
illustration="disconnected"
11+
py="space_64"
12+
>
13+
<Link isExternal href={`${APP_URL}/support`} variant="primary" size="sm">
14+
Contact Support
15+
</Link>
16+
</EmptyState>
17+
);
18+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import {
2+
Box,
3+
TableContainer,
4+
Table,
5+
Tr,
6+
Tbody,
7+
Td as ChakraTd,
8+
TableCellProps,
9+
Skeleton,
10+
} from '@chakra-ui/react';
11+
12+
const Td = (props: TableCellProps) => (
13+
<ChakraTd {...props} p="space_16" pr="space_64" _last={{ pr: 'space_56' }} />
14+
);
15+
16+
export default function CookbookTableLoading() {
17+
return (
18+
<Box w="full" overflow="auto">
19+
<TableContainer>
20+
<Table variant="simple">
21+
<Tbody>
22+
{[1, 2, 3, 4, 5, 6, 7].map((num, i) => (
23+
<Tr
24+
key={`loading-${num + i}`}
25+
p="space_16"
26+
border="1px"
27+
borderColor="neutral.50"
28+
bg="neutral.0"
29+
_dark={{ bg: 'neutral.100', borderColor: 'base.onyx' }}
30+
_hover={{
31+
bg: 'neutral.25',
32+
_dark: { bg: 'base.onyx' },
33+
}}
34+
>
35+
<Td>
36+
<Skeleton h="26px" w="24px" />
37+
</Td>
38+
<Td>
39+
<Skeleton h="26px" w="250px" />
40+
</Td>
41+
<Td>
42+
<Skeleton h="26px" w="220px" />
43+
</Td>
44+
<Td>
45+
<Skeleton h="26px" w="100px" />
46+
</Td>
47+
<Td>
48+
<Skeleton h="26px" w="62px" />
49+
</Td>
50+
<Td>
51+
<Skeleton h="26px" w="90px" />
52+
</Td>
53+
<Td>
54+
<Skeleton h="26px" w="90px" />
55+
</Td>
56+
</Tr>
57+
))}
58+
</Tbody>
59+
</Table>
60+
</TableContainer>
61+
</Box>
62+
);
63+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Button, Tooltip } from '@chakra-ui/react';
2+
import { HeartFilledIcon, HeartIcon } from '@codiga/codiga-components';
3+
import { useUser } from 'renderer/components/UserContext';
4+
5+
export type FavoriteProps = {
6+
isSubscribed: boolean;
7+
onSubscribe: () => void;
8+
onUnsubscribe: () => void;
9+
};
10+
11+
export default function Favorite({
12+
isSubscribed,
13+
onSubscribe,
14+
onUnsubscribe,
15+
}: FavoriteProps) {
16+
const { id: userId } = useUser();
17+
18+
return (
19+
<Tooltip
20+
shouldWrapChildren
21+
label="Log in to favorite"
22+
isDisabled={!!userId}
23+
>
24+
<Button
25+
variant="unstyled"
26+
minW="12px"
27+
h="26px"
28+
d="flex"
29+
justifyContent="center"
30+
alignItems="center"
31+
onClick={isSubscribed ? onUnsubscribe : onSubscribe}
32+
boxShadow="none !important"
33+
>
34+
{isSubscribed ? (
35+
<HeartFilledIcon h="10px" w="10px" color="base.rose" />
36+
) : (
37+
<HeartIcon h="10px" w="10px" />
38+
)}
39+
</Button>
40+
</Tooltip>
41+
);
42+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { useMutation } from '@apollo/client';
2+
import { useToast } from '@codiga/codiga-components';
3+
import {
4+
SUBSCRIBE_TO_COOKBOOK,
5+
UNSUBSCRIBE_TO_COOKBOOK,
6+
} from 'renderer/graphql/mutations';
7+
import {
8+
GET_SHARED_COOKBOOKS,
9+
GET_USER_COOKBOOKS,
10+
GET_USER_SUBSCRIBED_COOKBOOKS,
11+
} from 'renderer/graphql/queries';
12+
import {
13+
GET_SHARED_COOKBOOKS_VARIABLES,
14+
GET_USER_COOKBOOKS_VARIABLES,
15+
GET_USER_SUBSCRIBED_COOKBOOKS_VARIABLES,
16+
} from 'renderer/graphql/variables';
17+
import Favorite, { FavoriteProps } from './Favorite';
18+
19+
type FavoriteCookbookProps = Pick<FavoriteProps, 'isSubscribed'> & {
20+
cookbookId: number;
21+
};
22+
23+
const cookbookRefetches = [
24+
{
25+
query: GET_USER_COOKBOOKS,
26+
variables: GET_USER_COOKBOOKS_VARIABLES,
27+
},
28+
{
29+
query: GET_USER_SUBSCRIBED_COOKBOOKS,
30+
variables: GET_USER_SUBSCRIBED_COOKBOOKS_VARIABLES,
31+
},
32+
{
33+
query: GET_SHARED_COOKBOOKS,
34+
variables: GET_SHARED_COOKBOOKS_VARIABLES,
35+
},
36+
];
37+
38+
export default function FavoriteCookbook({
39+
isSubscribed,
40+
cookbookId,
41+
}: FavoriteCookbookProps) {
42+
const toast = useToast();
43+
44+
const [favoriteCookbook] = useMutation(SUBSCRIBE_TO_COOKBOOK);
45+
const [unfavoriteCookbook] = useMutation(UNSUBSCRIBE_TO_COOKBOOK);
46+
47+
const onFavoriteCookbook = async () => {
48+
try {
49+
await favoriteCookbook({
50+
variables: {
51+
id: cookbookId,
52+
},
53+
awaitRefetchQueries: true,
54+
refetchQueries: cookbookRefetches,
55+
});
56+
} catch (err) {
57+
toast({
58+
status: 'error',
59+
description: 'An error occurred. Please try again.',
60+
});
61+
}
62+
};
63+
64+
const onUnfavoriteCookbook = async () => {
65+
try {
66+
await unfavoriteCookbook({
67+
variables: {
68+
id: cookbookId,
69+
},
70+
awaitRefetchQueries: true,
71+
refetchQueries: cookbookRefetches,
72+
});
73+
} catch (err) {
74+
toast({
75+
status: 'error',
76+
description: 'An error occurred. Please try again.',
77+
});
78+
}
79+
};
80+
81+
return (
82+
<Favorite
83+
isSubscribed={isSubscribed}
84+
onSubscribe={onFavoriteCookbook}
85+
onUnsubscribe={onUnfavoriteCookbook}
86+
/>
87+
);
88+
}

0 commit comments

Comments
 (0)