Skip to content

Commit

Permalink
Merge pull request #73 from fga-eps-mds/142-gerar-relatorios-de-movim…
Browse files Browse the repository at this point in the history
…entacoes

142 gerar relatorios de movimentacoes
  • Loading branch information
JPedroCh authored Jul 10, 2023
2 parents 4c87f9a + f197da3 commit 6a9d4e5
Show file tree
Hide file tree
Showing 9 changed files with 582 additions and 39 deletions.
7 changes: 5 additions & 2 deletions src/components/form-fields/date/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type Props<FormValues extends FieldValues> = Omit<
startDate?: Date;
endDate?: Date;
monthPicker?: boolean;
yearPicker?: boolean;
outsideModal?: boolean;
};

Expand All @@ -55,11 +56,12 @@ export function Datepicker<FormValues extends FieldValues>({
label,
placeHolder,
border = true,
yearPicker = false,
outsideModal = false,
rules,
startDate,
endDate,
monthPicker = false,
outsideModal = false,
...props
}: Props<FormValues>) {
const {
Expand Down Expand Up @@ -106,6 +108,7 @@ export function Datepicker<FormValues extends FieldValues>({
minDate={lowerDate}
maxDate={higherDate}
showMonthYearPicker={monthPicker}
showYearPicker={yearPicker}
customInput={
border ? (
<Input borderColor="#212121" fontSize="sm" />
Expand Down Expand Up @@ -139,6 +142,7 @@ export function Datepicker<FormValues extends FieldValues>({
minDate={lowerDate}
maxDate={higherDate}
showMonthYearPicker={monthPicker}
showYearPicker={yearPicker}
customInput={
border ? (
<Input borderColor="#212121" fontSize="sm" />
Expand All @@ -162,7 +166,6 @@ export function Datepicker<FormValues extends FieldValues>({
<Icon as={BsCalendar3} color="#212121" fontSize="lg" />
</InputRightElement>
</InputGroup>

<FormErrorMessage>{error && error.message}</FormErrorMessage>
</FormControl>
);
Expand Down
215 changes: 215 additions & 0 deletions src/components/movements-reports/pdf/document.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import {
Document,
Page,
Text,
View,
StyleSheet,
Image,
Font,
} from '@react-pdf/renderer';
import { movement } from '@/pages/movements/MovementControl';
import { formatDate } from '@/utils/format-date';

interface MovementsPdfProps {
movements: movement[];
title: string;
}

Font.register({
family: 'Arial',
fonts: [
{
src: 'https://fonts.cdnfonts.com/s/29107/ARIALMTMEDIUM.woff',
fontStyle: 'normal',
fontWeight: 400,
},
{
src: 'https://fonts.cdnfonts.com/s/29107/ARIALBOLDMT.woff',
fontStyle: 'bold',
fontWeight: 700,
},
],
});

export function MovementsPDF({ title, movements }: MovementsPdfProps) {
const styles = StyleSheet.create({
page: {
flexDirection: 'column',
padding: 20,
fontFamily: 'Arial',
},
header: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
caption: {
fontSize: 8,
},
title: {
paddingTop: 24,
textTransform: 'uppercase',
fontSize: 20,
fontWeight: 700,
},
subtitle: {
fontSize: 12,
paddingBottom: 24,
},
locale: {
paddingBottom: 16,
fontSize: 12,
fontWeight: 700,
},
logo: {
width: 50,
height: 66,
marginBottom: 4,
},
tableHeader: {
backgroundColor: '#D8D8D8',
flexDirection: 'row',
marginTop: 8,
borderBottomWidth: 1,
borderTopWidth: 1,
borderBottomColor: '#000',
minHeight: 24,
alignItems: 'center',
},
columnHeader: {
color: '#000',
flex: 1,
textAlign: 'center',
fontSize: 8,
fontWeight: 'bold',
},
tableRow: {
flexDirection: 'row',
borderBottomWidth: 1,
borderBottomColor: '#000',
minHeight: 24,
alignItems: 'center',
},
rowData: {
fontSize: 8,
flex: 1,
textAlign: 'center',
paddingRight: 15,
},
signature: {
marginTop: 200,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
});

const formattedEmissionDate = (): string => {
const currentEmissionDate = new Date();
const emissionDay = currentEmissionDate
.getDate()
.toString()
.padStart(2, '0');
const emissionMonth = (currentEmissionDate.getMonth() + 1)
.toString()
.padStart(2, '0');
const emissionYear = currentEmissionDate
.getFullYear()
.toString()
.padStart(4, '0');

const emissionHours = currentEmissionDate
.getHours()
.toString()
.padStart(2, '0');
const emissionMinutes = currentEmissionDate
.getMinutes()
.toString()
.padStart(2, '0');
const emissionSeconds = currentEmissionDate
.getSeconds()
.toString()
.padStart(2, '0');

return `${emissionDay}/${emissionMonth}/${emissionYear} - ${emissionHours}:${emissionMinutes}:${emissionSeconds}`;
};

return (
<Document>
<Page size="A4" style={styles.page} orientation="landscape">
<View style={styles.header}>
<Image src="/PoliciaCivilLogo.jpeg" style={styles.logo} />
<Text style={styles.caption}>ESTADO DE GOIÁS</Text>
<Text style={styles.caption}>DIRETORIA GERAL DA POLÍCIA CIVIL</Text>
<Text style={styles.caption}>
SUPERINTENDÊNCIA DE GESTÃO INTEGRADA
</Text>
<Text style={styles.caption}>
DIVISÃO DE SUPORTE TÉCNICO EM INFORMÁTICA
</Text>
<Text style={styles.title}>{title}</Text>
<Text style={styles.subtitle}>
Sistema de Controle Interno da DSTI
</Text>
</View>
<Text style={styles.caption}>
Data da emissão: {formattedEmissionDate()}
</Text>
<View style={styles.tableHeader}>
<Text style={{ ...styles.columnHeader, maxWidth: 24 }}>Item</Text>
<Text style={{ ...styles.columnHeader, minWidth: 80, maxWidth: 100 }}>
Tombamento
</Text>
<Text style={{ ...styles.columnHeader, minWidth: 60, maxWidth: 80 }}>
Tipo
</Text>
<Text style={{ ...styles.columnHeader, minWidth: 45, maxWidth: 55 }}>
Marca
</Text>
<Text style={{ ...styles.columnHeader, minWidth: 70 }}>
Descrição
</Text>
<Text style={{ ...styles.columnHeader, minWidth: 70, maxWidth: 90 }}>
Lotação
</Text>
<Text style={{ ...styles.columnHeader, minWidth: 60, maxWidth: 80 }}>
Status
</Text>
<Text style={{ ...styles.columnHeader, maxWidth: 56 }}>
Data da Movimentação
</Text>
</View>
{movements.map((move: movement, moveIndex: number) =>
move.equipments.map((equipment: any, equipmentIndex: number) => (
<View style={styles.tableRow} key={equipment?.id}>
<Text style={{ ...styles.rowData, maxWidth: 24 }}>
{equipmentIndex + 1}
</Text>
<Text style={{ ...styles.rowData, minWidth: 80, maxWidth: 100 }}>
{equipment?.tippingNumber}
</Text>
<Text style={{ ...styles.rowData, minWidth: 60, maxWidth: 80 }}>
{equipment?.type?.name}
</Text>
<Text style={{ ...styles.rowData, minWidth: 45, maxWidth: 55 }}>
{equipment?.brand?.name}
</Text>
<Text style={{ ...styles.rowData, textAlign: 'center' }}>
{equipment?.description}
</Text>
<Text style={{ ...styles.rowData, minWidth: 70, maxWidth: 90 }}>
{move.destination.name}
</Text>
<Text style={{ ...styles.rowData, minWidth: 60, maxWidth: 80 }}>
{equipment?.situacao}
</Text>
<Text style={{ ...styles.rowData, maxWidth: 56 }}>
{formatDate(move?.date)}
</Text>
</View>
))
)}
</Page>
</Document>
);
}
88 changes: 88 additions & 0 deletions src/components/movements-reports/pdf/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { Flex, Text, Button } from '@chakra-ui/react';
import { PDFDownloadLink } from '@react-pdf/renderer';
import { MdDescription } from 'react-icons/md';
import { useCallback } from 'react';
import { CSVLink } from 'react-csv';
import { utils, writeFile } from 'xlsx';
import { Modal } from '@/components/modal';
import { movement } from '@/pages/movements/MovementControl';
import { formatDate } from '@/utils/format-date';
import { MovementsPDF } from './document';

type ReportModalProps = {
isOpen: boolean;
onClose(): void;
type: string;
movements: movement[];
};

export function ReportModal({
isOpen,
onClose,
type,
movements,
}: ReportModalProps) {
const onCloseCallback = () => {
onClose();
};

const formattedDate = formatDate(new Date());

const exportFile = useCallback(() => {
const ws = utils.json_to_sheet(movements);
const wb = utils.book_new();
utils.book_append_sheet(wb, ws, 'Data');
writeFile(wb, `relatorio_movimentacoes_${formattedDate}.xls`);
}, [formattedDate, movements]);

return (
<Modal
title="Relatório de movimentações"
isOpen={isOpen}
onClose={onCloseCallback}
size="2xl"
>
<Text
textAlign="center"
mt="1rem"
style={{ display: 'flex', alignItems: 'center' }}
fontWeight="bold"
fontSize="larger"
>
<MdDescription size={40} />
{`Relatório em ${type}`}
</Text>
<Flex gap="4rem" mt="2rem" mb="1rem" justify="center">
<Button variant="secondary" onClick={onCloseCallback}>
Cancelar
</Button>
{type === 'pdf' && (
<PDFDownloadLink
document={
<MovementsPDF
title="Relatório de movimentações"
movements={movements}
/>
}
fileName={`relatorio_movimentacoes_${formattedDate}`}
>
<Button>Imprimir</Button>
</PDFDownloadLink>
)}
{type === 'csv' && (
<CSVLink
data={movements}
type="csv"
target="_blank"
filename={`relatorio_movimentacoes_${formattedDate}.csv`}
separator=";"
>
<Button>Imprimir</Button>
</CSVLink>
)}

{type === 'xls' && <Button onClick={exportFile}>Imprimir</Button>}
</Flex>
</Modal>
);
}
Loading

0 comments on commit 6a9d4e5

Please sign in to comment.