This commit is contained in:
Nathan Bierema 2025-05-31 13:58:39 -04:00
parent 5940aaba9a
commit 6a1f3194f8
7 changed files with 98 additions and 76 deletions

View File

@ -1,7 +1,7 @@
import PokemonView from './features/pokemon/PokemonView';
import PostsView from './features/posts/PostsView';
import { Box, Flex, Heading } from '@chakra-ui/react';
import { Link, UnorderedList, ListItem } from '@chakra-ui/react';
import { Box, Flex, Heading, List } from '@chakra-ui/react';
import { Link } from '@chakra-ui/react';
import { Code } from '@chakra-ui/react';
import * as React from 'react';
import { DevToolsSelector } from './features/DevTools/DevToolsSelector';
@ -27,44 +27,48 @@ export function App() {
</Box>
</Flex>
<Flex p="2" as="footer">
<UnorderedList p="2">
<ListItem>
<List.Root p="2">
<List.Item>
<Link
className="link"
isExternal
target="_blank"
rel="noopener noreferrer"
href="https://github.com/FaberVitale/redux-devtools/tree/feat/rtk-query-monitor/packages/redux-devtools-rtk-query-monitor/demo"
>
demo source
</Link>
</ListItem>
<ListItem>
</List.Item>
<List.Item>
<Link
className="link"
isExternal
target="_blank"
rel="noopener noreferrer"
href="https://github.com/FaberVitale/redux-devtools/tree/feat/rtk-query-monitor/packages/redux-devtools-rtk-query-monitor"
>
@redux-devtools/rtk-query-monitor source
</Link>
</ListItem>
<ListItem>
</List.Item>
<List.Item>
<Link
className="link"
isExternal
target="_blank"
rel="noopener noreferrer"
href="https://github.com/reduxjs/redux-toolkit/tree/master/examples/query/react/polling"
>
polling example
</Link>
</ListItem>
<ListItem>
</List.Item>
<List.Item>
<Link
className="link"
isExternal
target="_blank"
rel="noopener noreferrer"
href="https://github.com/reduxjs/redux-toolkit/tree/master/examples/query/react/mutations"
>
mutations example
</Link>
</ListItem>
</UnorderedList>
</List.Item>
</List.Root>
</Flex>
</main>
);

View File

@ -14,7 +14,7 @@ export function DevToolsSelector() {
return (
<Box as="section" p="2">
<Heading as="h2">Set active devTools</Heading>
<ButtonGroup variant="outline" spacing="4" p="4">
<ButtonGroup variant="outline" gap="4" p="4">
<Button
aria-selected={!extensionEnabled}
colorScheme="blue"

View File

@ -1,15 +1,17 @@
import React, { useState } from 'react';
import { Button, Select } from '@chakra-ui/react';
import { Button, createListCollection, Portal, Select } from '@chakra-ui/react';
import { useGetPokemonByNameQuery } from '../../services/pokemon';
import type { PokemonName } from '../../pokemon.data';
const intervalOptions = [
{ label: 'Off', value: 0 },
{ label: '3s', value: 3000 },
{ label: '5s', value: 5000 },
{ label: '10s', value: 10000 },
{ label: '1m', value: 60000 },
];
const intervalOptions = createListCollection({
items: [
{ label: 'Off', value: 0 },
{ label: '3s', value: 3000 },
{ label: '5s', value: 5000 },
{ label: '10s', value: 10000 },
{ label: '1m', value: 60000 },
],
});
export function Pokemon({ name }: { name: PokemonName }) {
const [pollingInterval, setPollingInterval] = useState(60000);
@ -41,19 +43,37 @@ export function Pokemon({ name }: { name: PokemonName }) {
/>
</div>
<div>
<label style={{ display: 'block' }}>Polling interval</label>
<Select
value={pollingInterval}
onChange={({ target: { value } }) =>
setPollingInterval(Number(value))
}
<Select.Root
collection={intervalOptions}
value={[pollingInterval.toString()]}
onValueChange={({ value }) => setPollingInterval(Number(value))}
>
{intervalOptions.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</Select>
<Select.HiddenSelect />
<Select.Label>Polling interval</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Polling interval" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{intervalOptions.items.map((intervalOption) => (
<Select.Item
item={intervalOption}
key={intervalOption.value}
>
{intervalOption.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
</div>
<div>
<Button

View File

@ -15,8 +15,8 @@ import {
Input,
Spacer,
Stack,
useToast,
} from '@chakra-ui/react';
import { toaster } from '../../components/ui/toaster';
const EditablePostName = ({
name: initialName,
@ -50,8 +50,8 @@ const EditablePostName = ({
</Box>
<Spacer />
<Box>
<Stack spacing={4} direction="row" align="center">
<Button onClick={handleUpdate} isLoading={isLoading}>
<Stack gap={4} direction="row" align="center">
<Button onClick={handleUpdate} loading={isLoading}>
Update
</Button>
<CloseButton bg="red" onClick={handleCancel} disabled={isLoading} />
@ -75,8 +75,6 @@ export const PostDetail = () => {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const toast = useToast();
const [isEditing, setIsEditing] = useState(false);
const { data: post, isLoading } = useGetPostQuery(id!);
@ -108,12 +106,12 @@ export const PostDetail = () => {
try {
await updatePost({ id: id!, name }).unwrap();
} catch {
toast({
toaster.create({
title: 'An error occurred',
description: "We couldn't save your changes, try again!",
status: 'error',
type: 'error',
duration: 2000,
isClosable: true,
closable: true,
});
} finally {
setIsEditing(false);
@ -129,7 +127,7 @@ export const PostDetail = () => {
</Box>
<Spacer />
<Box>
<Stack spacing={4} direction="row" align="center">
<Stack gap={4} direction="row" align="center">
<Button
onClick={() => setIsEditing(true)}
disabled={isDeleting || isUpdating}

View File

@ -2,20 +2,15 @@ import {
Box,
Button,
Center,
Divider,
Field,
Flex,
FormControl,
FormLabel,
FormatNumber,
Heading,
Input,
List,
ListIcon,
ListItem,
Separator,
Spacer,
Stat,
StatLabel,
StatNumber,
useToast,
} from '@chakra-ui/react';
import { Route, Routes, useNavigate } from 'react-router-dom';
import { MdBook } from 'react-icons/md';
@ -26,12 +21,12 @@ import {
useGetPostsQuery,
} from '../../services/posts';
import { PostDetail } from './PostDetail';
import { toaster } from '../../components/ui/toaster';
const AddPost = () => {
const initialValue = { name: '' };
const [post, setPost] = useState<Pick<Post, 'name'>>(initialValue);
const [addPost, { isLoading }] = useAddPostMutation();
const toast = useToast();
const handleChange = ({ target }: React.ChangeEvent<HTMLInputElement>) => {
setPost((prev) => ({
@ -45,12 +40,12 @@ const AddPost = () => {
await addPost(post).unwrap();
setPost(initialValue);
} catch {
toast({
toaster.create({
title: 'An error occurred',
description: "We couldn't save your post, try again!",
status: 'error',
type: 'error',
duration: 2000,
isClosable: true,
closable: true,
});
}
};
@ -58,11 +53,11 @@ const AddPost = () => {
return (
<Flex p={'5px 0'} flexDirection="row" flexWrap="wrap" maxWidth={'85%'}>
<Box flex={'5 0 auto'} padding="0 5px 0 0">
<FormControl
<Field.Root
flexDirection="column"
isInvalid={Boolean(post.name.length < 3 && post.name)}
invalid={Boolean(post.name.length < 3 && post.name)}
>
<FormLabel htmlFor="name">Post name</FormLabel>
<Field.Label htmlFor="name">Post name</Field.Label>
<Input
id="name"
name="name"
@ -70,13 +65,13 @@ const AddPost = () => {
value={post.name}
onChange={handleChange}
/>
</FormControl>
</Field.Root>
</Box>
<Box>
<Button
mt={8}
colorScheme="purple"
isLoading={isLoading}
loading={isLoading}
onClick={handleAddPost}
>
Add Post
@ -99,13 +94,16 @@ const PostList = () => {
}
return (
<List spacing={3}>
<List.Root gap={3}>
{posts.map(({ id, name }) => (
<ListItem key={id} onClick={() => navigate(`/posts/${id}`)}>
<ListIcon as={MdBook} color="green.500" /> {name}
</ListItem>
<List.Item key={id} onClick={() => navigate(`/posts/${id}`)}>
<List.Indicator asChild color="green.500">
<MdBook />
</List.Indicator>
{name}
</List.Item>
))}
</List>
</List.Root>
);
};
@ -115,10 +113,12 @@ export const PostsCountStat = () => {
if (!posts) return null;
return (
<Stat>
<StatLabel>Active Posts</StatLabel>
<StatNumber>{posts?.length}</StatNumber>
</Stat>
<Stat.Root>
<Stat.Label>Active Posts</Stat.Label>
<Stat.ValueText>
<FormatNumber value={posts?.length} />
</Stat.ValueText>
</Stat.Root>
);
};
@ -134,9 +134,9 @@ export const PostsManager = () => {
<PostsCountStat />
</Box>
</Flex>
<Divider />
<Separator />
<AddPost />
<Divider />
<Separator />
<Flex wrap="wrap">
<Box flex={1} borderRight="1px solid #eee">
<Box p={4} borderBottom="1px solid #eee">

View File

@ -8,6 +8,7 @@ import DevTools from './features/DevTools/DevTools';
import { BrowserRouter } from 'react-router-dom';
import { App } from './App';
import { worker } from './mocks/browser';
import { Toaster } from './components/ui/toaster';
function renderApp() {
const rootElement = document.getElementById('root');
@ -17,6 +18,7 @@ function renderApp() {
<ChakraProvider>
<BrowserRouter>
<App />
<Toaster />
<DevTools />
</BrowserRouter>
</ChakraProvider>

View File

@ -1,5 +1,3 @@
/// <reference types="react-scripts" />
declare module '@redux-devtools/app';
declare module 'remote-redux-devtools';