Skip to content

Commit

Permalink
[FEAT] - Create Dashboard page (#218)
Browse files Browse the repository at this point in the history
* feat(dashboard): initial config to create dashboard page

* feat(dashboard): create initial dashboard page and add semantic classes to header and footer

* feat(dashboard): create overview cards

* feat(dashboard): create need supplies card

* feat(dashboar): add dashboard service

* feat(dashboard): add chevron right

* feat(dashboard): add link to filters page

* Update src/components/BurgerMenu/BurgerMenu.tsx

Co-authored-by: Rafael Alves <138794120+rafael-alves-cs@users.noreply.github.com>

* feat(dashboard): create need supplies

* feat(dashboard): integration with service

* fix(dashboard): remove console log

* fix(donation): fix errors in other issues

* fix(sync): merge adjust

---------

Co-authored-by: mateus.nogueira-extern <mateus.nogueira-extern@renault.com>
Co-authored-by: Rafael Alves <138794120+rafael-alves-cs@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 14, 2024
1 parent 740b49c commit 95bb703
Show file tree
Hide file tree
Showing 18 changed files with 404 additions and 67 deletions.
5 changes: 5 additions & 0 deletions src/components/BurgerMenu/BurgerMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ const BurgerMenu = () => {
link="/apoiadores"
icon={<HeartHandshake className="w-5 h-5" />}
/>
<BurguerMenuItem
label="Visão Geral"
link="/dashboard"
icon={<Info className="w-4 h-4" />}
/>
<Separator />
{partners.length > 0 && (
<Fragment>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const Footer = React.forwardRef<
const { className = '', ...rest } = props;

return (
<div
<footer
ref={ref}
{...rest}
className={cn(
Expand Down Expand Up @@ -39,7 +39,7 @@ const Footer = React.forwardRef<
</a>
<Heart className="h-3 w-3 stroke-white fill-white" />
</span>
</div>
</footer>
);
});

Expand Down
102 changes: 52 additions & 50 deletions src/components/ui/form.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { Slot } from "@radix-ui/react-slot"
import * as React from 'react';
import * as LabelPrimitive from '@radix-ui/react-label';
import { Slot } from '@radix-ui/react-slot';
import {
Controller,
ControllerProps,
FieldPath,
FieldValues,
FormProvider,
useFormContext,
} from "react-hook-form"
} from 'react-hook-form';

import { cn } from "@/lib/utils"
import { Label } from "@/components/ui/label"
import { cn } from '@/lib/utils';
import { Label } from '@/components/ui/label';

const Form = FormProvider
const Form = FormProvider;

type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> = {
name: TName
}
name: TName;
};

const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue
)
);

const FormField = <
TFieldValues extends FieldValues = FieldValues,
Expand All @@ -36,21 +36,21 @@ const FormField = <
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
</FormFieldContext.Provider>
)
}
);
};

const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext)
const itemContext = React.useContext(FormItemContext)
const { getFieldState, formState } = useFormContext()
const fieldContext = React.useContext(FormFieldContext);
const itemContext = React.useContext(FormItemContext);
const { getFieldState, formState } = useFormContext();

const fieldState = getFieldState(fieldContext.name, formState)
const fieldState = getFieldState(fieldContext.name, formState);

if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>")
throw new Error('useFormField should be used within <FormField>');
}

const { id } = itemContext
const { id } = itemContext;

return {
id,
Expand All @@ -59,53 +59,54 @@ const useFormField = () => {
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
}
}
};
};

type FormItemContextValue = {
id: string
}
id: string;
};

const FormItemContext = React.createContext<FormItemContextValue>(
{} as FormItemContextValue
)
);

const FormItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const id = React.useId()
const id = React.useId();

return (
<FormItemContext.Provider value={{ id }}>
<div ref={ref} className={cn("space-y-2", className)} {...props} />
<div ref={ref} className={cn('space-y-2', className)} {...props} />
</FormItemContext.Provider>
)
})
FormItem.displayName = "FormItem"
);
});
FormItem.displayName = 'FormItem';

const FormLabel = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => {
const { error, formItemId } = useFormField()
const { error, formItemId } = useFormField();

return (
<Label
ref={ref}
className={cn(error && "text-destructive", className)}
className={cn(error && 'text-destructive', className)}
htmlFor={formItemId}
{...props}
/>
)
})
FormLabel.displayName = "FormLabel"
);
});
FormLabel.displayName = 'FormLabel';

const FormControl = React.forwardRef<
React.ElementRef<typeof Slot>,
React.ComponentPropsWithoutRef<typeof Slot>
>(({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
const { error, formItemId, formDescriptionId, formMessageId } =
useFormField();

return (
<Slot
Expand All @@ -119,52 +120,53 @@ const FormControl = React.forwardRef<
aria-invalid={!!error}
{...props}
/>
)
})
FormControl.displayName = "FormControl"
);
});
FormControl.displayName = 'FormControl';

const FormDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField()
const { formDescriptionId } = useFormField();

return (
<p
ref={ref}
id={formDescriptionId}
className={cn("text-sm text-muted-foreground", className)}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
)
})
FormDescription.displayName = "FormDescription"
);
});
FormDescription.displayName = 'FormDescription';

const FormMessage = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField()
const body = error ? String(error?.message) : children
const { error, formMessageId } = useFormField();
const body = error ? String(error?.message) : children;

if (!body) {
return null
return null;
}

return (
<p
ref={ref}
id={formMessageId}
className={cn("text-sm font-medium text-destructive", className)}
className={cn('text-sm font-medium text-destructive', className)}
{...props}
>
{body}
</p>
)
})
FormMessage.displayName = "FormMessage"
);
});
FormMessage.displayName = 'FormMessage';

export {
// eslint-disable-next-line react-refresh/only-export-components
useFormField,
Form,
FormItem,
Expand All @@ -173,4 +175,4 @@ export {
FormDescription,
FormMessage,
FormField,
}
};
24 changes: 24 additions & 0 deletions src/hooks/useDashboard/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export interface IUseDashboardOptions {
cache?: boolean;
}

export interface ISupplieShelter {
id: string;
name: string;
}
export interface ISuppliesCategories {
categoryId: string;
categoryName: string;
priority100: number;
priority10: number;
priority1: number;
}

export interface IUseDashboardData {
allShelters?: number;
allPeopleSheltered?: number;
shelterAvailable?: number;
shelterFull?: number;
shelterWithoutInformation?: number;
categoriesWithPriorities?: ISuppliesCategories[];
}
58 changes: 58 additions & 0 deletions src/hooks/useDashboard/useDashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useState, useCallback, useEffect } from 'react';
import { AxiosRequestConfig } from 'axios';

import { api } from '@/api';
import { IServerResponse } from '@/types';

import { PaginatedQueryPath } from '../usePaginatedQuery/paths';
import { IUseDashboardData, IUseDashboardOptions } from './types';

const useDashboard = (options: IUseDashboardOptions = {}) => {
const { cache } = options;
const [loading, setLoading] = useState<boolean>(false);
const [data, setData] = useState<IUseDashboardData>({
allShelters: 0,
allPeopleSheltered: 0,
shelterAvailable: 0,
shelterFull: 0,
shelterWithoutInformation: 0,
});

const refresh = useCallback(
(config: AxiosRequestConfig<any> = {}, append: boolean = false) => {
const headers = config.headers ?? {};
if (cache) headers['x-app-cache'] = 'true';
if (!append) setLoading(true);
api
.get<IServerResponse<any>>(PaginatedQueryPath.Dashboard, {
...config,
headers,
})
.then(({ data }) => {
if (append) {
setData((prev) => ({
...prev,
...data.data,
}));
} else {
setData((prev) => ({
...prev,
...data.data,
}));
}
})
.finally(() => {
if (!append) setLoading(false);
});
},
[cache]
);

useEffect(() => {
refresh();
}, [refresh]);

return { data, loading, refresh };
};

export { useDashboard };
8 changes: 8 additions & 0 deletions src/hooks/useDonations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ export interface IUseDonationsData {
results: IDonationsData[];
}

export interface IDonationOrderSupplies {
quantity: number;
supply: {
measure: string;
name: string;
};
}

export interface IDonationsData {
id: string;
user: {
Expand Down
1 change: 1 addition & 0 deletions src/hooks/usePaginatedQuery/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export enum PaginatedQueryPath {
ShelterCities = '/shelters/cities',
SupplyCategories = '/supply-categories',
Supplies = '/supplies',
Dashboard = '/dashboard',
DonationOrder = '/donation/order',
}
23 changes: 8 additions & 15 deletions src/hooks/useShelters/useShelters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { api } from '@/api';
import { IServerResponse } from '@/types';
import { IPaginatedResponse } from '../usePaginatedQuery/types';
import { IUseShelterOptions, IUseSheltersData } from './types';
import { PaginatedQueryPath } from '../usePaginatedQuery/paths';

const useShelters = (options: IUseShelterOptions = {}) => {
const { cache } = options;
Expand All @@ -24,7 +25,7 @@ const useShelters = (options: IUseShelterOptions = {}) => {
headers['x-app-cache'] = 'true';
if (!append) setLoading(true);
api
.get<IServerResponse<any>>('/shelters', {
.get<IServerResponse<any>>(PaginatedQueryPath.Shelters, {
...config,
headers,
params: {
Expand All @@ -36,22 +37,14 @@ const useShelters = (options: IUseShelterOptions = {}) => {
},
})
.then(({ data }) => {
if (append) {
setData((prev) => ({
...prev,
...data.data,
results: [...prev.results, ...data.data.results],
}));
} else {
setData((prev) => ({
...prev,
...data.data,
results: [...data.data.results],
}));
}
setData((prev) => ({
...prev,
...data.data,
results: [...data.data.results],
}));
})
.finally(() => {
if (!append) setLoading(false);
setLoading(!append);
});
},
[cache]
Expand Down
Loading

0 comments on commit 95bb703

Please sign in to comment.