Skip to content

Commit

Permalink
create api logic deleteDelivery, routes; spec test getAllInvoices; fi…
Browse files Browse the repository at this point in the history
…x registerCustomer; install reactpdf, implement delete to app, implement reactpdf to deliveryInfo, update styles; b00tc4mp#156
  • Loading branch information
JackDev21 committed Aug 14, 2024
1 parent 8b4ebf2 commit e0557f6
Show file tree
Hide file tree
Showing 22 changed files with 927 additions and 69 deletions.
522 changes: 508 additions & 14 deletions staff/jose-canto/project/FactuClient/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions staff/jose-canto/project/FactuClient/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"@react-pdf/renderer": "^3.4.4",
"com": "file:../com",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@tailwind components;

@layer components {
.Confirm {
@apply absolute mx-auto w-auto flex-1 flex-col items-center rounded-lg bg-[#e4e4e4] p-4 shadow-custom-shadow;
}

.Confirm h2 {
@apply text-center text-2xl font-bold;
}

.Confirm p {
@apply mt-4 text-center;
}

.Confirm-Buttons {
@apply flex w-auto gap-10;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Button from "../core/Button"
import Title from "../Title"

import "./index.css"

export default function Confirm({ setShowConfirmDelete, handleDeleteDeliveryNote }) {
return (
<>
<div className="Confirm">
<Title level={2}>¿Seguro que quieres eliminar?</Title>
<div className="Confirm-Buttons">
<Button className="ConfirmButton" onClick={handleDeleteDeliveryNote}>
Aceptar
</Button>
<Button className="CancelButton" onClick={() => setShowConfirmDelete(!setShowConfirmDelete)}>
Cancelar
</Button>
</div>
</div>
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ import logic from "../../logic"
import RegisterCustomer from "../RegisterCustomerForm"
import EditProfileForm from "../EditProfileForm"

export default function Header({ className, iconUser, children, iconLeftHeader, onRegisterCustomer }) {
export default function Header({
className,
iconUser,
children,
iconLeftHeader,
onRegisterCustomer,
onDeleteDeliveryNote
}) {
const navigate = useNavigate()
const location = useLocation()
const [showRegisterCustomer, setShowRegisterCustomer] = useState(false)
Expand Down Expand Up @@ -111,6 +118,9 @@ export default function Header({ className, iconUser, children, iconLeftHeader,

{isCustomerProfilePathDeliveryNoteId && (
<div className="ContainerHeader">
<div onClick={onDeleteDeliveryNote} className="IconLeftHeader">
{iconLeftHeader}
</div>
<div className="IconUser">{iconUser}</div>
<div className="Children">{children}</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
.Button {
@apply mt-4 flex h-12 w-3/4 cursor-pointer items-center justify-center rounded-2xl border-[2px] border-white bg-custom-gradient p-2 text-2xl font-bold shadow-custom-shadow;
}

.Button:hover {
@apply border-[3px] border-black bg-black text-white;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
.MainDeliveryInfo {
@apply relative bottom-7;
}
.HeaderDeliveryInfo .IconLeftHeader {
@apply text-6xl;
}
.DeliveryWork {
@apply relative flex w-[90%] flex-col;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
import { useEffect, useState } from "react"
import { useParams } from "react-router-dom"
import { useParams, useNavigate } from "react-router-dom"
import { PDFDownloadLink } from "@react-pdf/renderer"

import { GiStabbedNote } from "react-icons/gi"
import { MdDeleteForever } from "react-icons/md"

import Header from "../Header"
import Main from "../core/Main"
import Time from "../core/Time"
import Footer from "../core/Footer"
import Confirm from "../Confirm"
import DeliveryNotePDF from "./DeliveryNotePDF"

import logic from "../../logic/index"

import "./DeliveryInfo.css"

export default function DeliveryInfo() {
const navigate = useNavigate()
const { deliveryNoteId } = useParams()
const [deliveryNote, setDeliveryNote] = useState(null)
const [total, setTotal] = useState(0)
const [showConfirmDelete, setShowConfirmDelete] = useState(false)

useEffect(() => {
try {
Expand All @@ -28,16 +34,41 @@ export default function DeliveryInfo() {
setTotal(calculateTotal)
})
.catch((error) => {
alert.error(error.message)
alert(error.message)
})
} catch (error) {
alert(error.message)
}
}, [deliveryNoteId])

const handleDeleteDeliveryNote = () => {
try {
//prettier-ignore
logic.deleteDeliveryNote(deliveryNoteId)
.then(() => {
navigate(-1)
})
.catch((error) => {
alert(error.message)
})
} catch (error) {
alert(error.message)
}
}

const handleShowConfirmDelete = () => {
setShowConfirmDelete(!showConfirmDelete)
}

return (
<>
<Header iconUser={<GiStabbedNote />} className={"HeaderDeliveryInfo"}></Header>
<Header
iconUser={<GiStabbedNote />}
iconLeftHeader={<MdDeleteForever />}
className={"HeaderDeliveryInfo"}
onDeleteDeliveryNote={handleShowConfirmDelete}
></Header>

<Main className={"MainDeliveryInfo"}>
<div className="DeliveryInfoCustomer">
{deliveryNote?.customer && <p>{deliveryNote.customer.companyName}</p>}
Expand All @@ -46,7 +77,7 @@ export default function DeliveryInfo() {
</div>
<div className="DeliveryWork">
<div className="TitleDateContainer">
{deliveryNote?.number && <p className="DeliveryNumber">Albarán nº:{deliveryNote.number}</p>}
{deliveryNote?.number && <p className="DeliveryNumber">Albarán nº: {deliveryNote.number}</p>}
{deliveryNote?.date && <Time className={"DeliveryDate"}>{deliveryNote.date}</Time>}
</div>
<div className="DeliveryTitleInfo">
Expand Down Expand Up @@ -75,9 +106,22 @@ export default function DeliveryInfo() {
<div className="ObservationsContainer">
{deliveryNote?.customer && <p className="Observations">Observaciones:{deliveryNote.observations}</p>}
</div>
<div className="DeliveryTotal">TOTAL: {total.toFixed(2)} </div>
<div className="DeliveryTotal">TOTAL: {total.toFixed(2)}</div>
</div>

{showConfirmDelete && (
<Confirm handleDeleteDeliveryNote={handleDeleteDeliveryNote} setShowConfirmDelete={handleShowConfirmDelete} />
)}
{deliveryNote && (
<PDFDownloadLink
document={<DeliveryNotePDF deliveryNote={deliveryNote} total={total} />}
fileName={`delivery-note-${deliveryNote.number}.pdf`}
>
{({ loading }) => (loading ? "Generando PDF..." : "Descargar PDF")}
</PDFDownloadLink>
)}
</Main>

<Footer>FactuClient</Footer>
</>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { Page, Text, View, Document, StyleSheet, Image } from "@react-pdf/renderer"

const styles = StyleSheet.create({
page: {
padding: 10,
backgroundColor: "aliceblue"
},
section: {
margin: 5,
padding: 5,
flexGrow: 1
},
headerRow: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 15
},
header: {
fontSize: 16,
textAlign: "center"
},
date: {
fontSize: 12,
textAlign: "center"
},
borderedSection: {
border: "1px solid black",
padding: 10,
marginBottom: 10,
flex: 1,
textAlign: "center"
},
companyInfo: {
backgroundColor: "#e0f7fa"
},
customerInfo: {
backgroundColor: "#f1f8e9"
},
infoRow: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 5,
fontSize: 12
},
workInfoHeader: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 5,
fontWeight: "bold",
fontSize: 14,
backgroundColor: "#d5cabd",
padding: 5
},
workInfo: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 5,
fontSize: 12
},
concept: {
flex: 3,
textAlign: "left"
},
quantity: {
flex: 1,
textAlign: "right"
},
price: {
flex: 1,
textAlign: "right"
},
totalAmount: {
flex: 1,
textAlign: "right"
},
total: {
marginTop: 20,
fontSize: 16,
textAlign: "right"
},
logo: {
width: 50,
height: 50,
marginBottom: 15
}
})

const DeliveryNotePDF = ({ deliveryNote, total }) => {
const formattedDate = new Date(deliveryNote.date).toLocaleDateString()

return (
<Document>
<Page size="A5" orientation="landscape" style={styles.page}>
<View style={styles.section}>
<Image style={styles.logo} src={deliveryNote.company.companyLogo} />

<View style={styles.headerRow}>
<Text style={styles.header}>Albarán nº: {deliveryNote.number}</Text>
<Text style={styles.date}>Fecha: {formattedDate}</Text>
</View>

<View style={styles.infoRow}>
<Text style={[styles.borderedSection, styles.companyInfo]}>
{deliveryNote.company.companyName}
{"\n"}
{deliveryNote.company.address}
{"\n"}
{deliveryNote.company.taxId}
{"\n"}
{deliveryNote.company.email}
</Text>
<View style={[styles.borderedSection, styles.customerInfo]}>
<Text style={{ fontWeight: "bold", textDecoration: "underline", marginBottom: 5 }}>Cliente:</Text>
<Text>
{deliveryNote.customer.companyName}
{"\n"}
{deliveryNote.customer.address}
{"\n"}
{deliveryNote.customer.taxId}
{"\n"}
{deliveryNote.customer.email}
</Text>
</View>
</View>

<View style={styles.workInfoHeader}>
<Text style={styles.concept}>Concepto</Text>
<Text style={styles.quantity}>Cantidad</Text>
<Text style={styles.price}>Precio</Text>
<Text style={styles.totalAmount}>Total</Text>
</View>
{deliveryNote.works.map((work) => (
<View key={work._id} style={styles.workInfo}>
<Text style={styles.concept}>{work.concept}</Text>
<Text style={styles.quantity}>{work.quantity.toFixed(2)}</Text>
<Text style={styles.price}>{work.price.toFixed(2)}</Text>
<Text style={styles.totalAmount}>{(work.quantity * work.price).toFixed(2)}</Text>
</View>
))}

<Text style={styles.total}>TOTAL: {total.toFixed(2)}</Text>
</View>
</Page>
</Document>
)
}

export default DeliveryNotePDF
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
}

.DeliveryLink {
@apply flex items-start;
@apply flex items-center;
}

.DeliveryNote {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import errors, { SystemError } from "com/errors.js"
import validate from "com/validate.js"

const deleteDeliveryNote = (deliveryNoteId) => {
validate.id(deliveryNoteId, "deliveryNoteId")

return fetch(`${import.meta.env.VITE_API_URL}/delivery-notes/${deliveryNoteId}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${sessionStorage.token}`
}
})
.catch(() => { throw new SystemError("connection error") })
.then(response => {
if (response.status === 204) return

return response.json()
.catch(() => { throw new SystemError("connection error") })
.then(body => {
const { error, message } = body
const constructor = errors[error]
throw new constructor(message)
})
})
}
export default deleteDeliveryNote
Loading

0 comments on commit e0557f6

Please sign in to comment.