Altbilgi içeriğine atla
PDF ARAçLARı

React'te PDF Dosyası Nasıl Oluşturulur

React uygulamasından PDF belgeleri oluşturma eğitimine hoş geldiniz! Bu öğreticide, PDF oluşturmak için çeşitli kütüphaneleri keşfedeceğiz ve React bileşenlerinizden doğrudan PDF dosyaları oluşturmak için popüler jsPDF kütüphanesini nasıl kullanacağınızı öğreneceğiz. O halde, başlayalım ve işe koyulalım!

PDF (Taşınabilir Belge Formatı), belgeleri paylaşmak ve yazdırmak için yaygın olarak kullanılan ve belge düzenini ile formatlamasını koruyan bir dosya formatıdır. Bir React web geliştiricisi olarak, React uygulamanızdan doğrudan faturalar, raporlar veya satış sözleşmeleri gibi PDF belgeleri oluşturmanız gereken senaryolarla karşılaşabilirsiniz.

Bir React PDF Kütüphanesi Seçmek

Bir React uygulamasında PDF belgeleri oluşturmak göz korkutucu bir görev olabilir, özellikle bu alana yeniyseniz. Neyse ki, bu süreci önemli ölçüde basitleştiren birkaç üçüncü taraf kütüphane emrimize amade. Her kütüphane, farklı kullanım durumlarına uygun, kendi benzersiz özellikleri ve yardımcı programları ile birlikte gelir. Bu kütüphaneleri biraz daha ayrıntılı inceleyelim.

jsPDF

jsPDF, JavaScript'ten PDF dosyaları oluşturmak için geliştiriciler arasında yaygın olarak popüler bir kütüphanedir. Ana satış noktalarından biri basitliğidir. Sözdizimi ve kullanımı oldukça basittir, böylece HTML içeriğinizi kısa sürede bir PDF dosyasına dönüştürebilirsiniz.

Bu, yazı tipi boyutunu ve rengini değiştirmekten sayfa yönünü ve boyutunu ayarlamaya kadar PDF'lerinizin formatını ve düzenini kontrol etmenize olanak tanır. jsPDF, hem tarayıcı hem de sunucu ortamlarında çalışan sağlam bir çözümdür ve geniş bir JavaScript uygulaması yelpazesi için mükemmel bir seçimdir.

pdfmake

pdfmake, saf JavaScript'te bir istemci/sunucu yanlısı PDF yazdırma çözümü olarak öne çıkıyor. Bu kütüphane, kapsamlı API'si ve esnek düzen seçenekleri sayesinde daha karmaşık PDF'ler oluşturmak için mükemmel bir seçimdir. pdfmake ile, belgenizin içeriğini ve yapısını basit bir JavaScript nesnesi kullanarak tanımlayabilir ve ardından geçerli bir PDF belgesine dönüştürebilirsiniz.

React-PDF

React-PDF, React bileşenlerini kullanarak PDF dosyaları oluşturmak için güçlü işlevsellik sağlayan benzersiz bir kütüphanedir. Belgelerinizi bir JavaScript nesnesinde manuel olarak yazmak yerine, yeniden kullanılabilir bileşenler ve özellikler kullanarak tipik bir React uygulaması oluşturur gibi PDF'nizi oluşturabilirsiniz. IronPDF web sitesi, React-PDF kütüphanesi kullanarak PDF oluşturma üzerine bir eğitim sunar.

Neden jsPDF'yi Seçmelisiniz?

Her üç kütüphanede React ile PDF belgeleri oluşturmak için güçlü araçlar sağlarken, toplulukta geniş kabul görmüş basitliği ve esnekliği nedeniyle bu öğreticide jsPDF kullanacağız. Yeni başlayanlar için daha düşük bir başlangıç bariyeri sağlar ve sağlam özellik seti, birçok kullanım durumu için uygun bir seçim haline getirir. jsPDF ile keşfedeceğimiz ilkeler, PDF'ler oluşturmak için size sağlam bir temel sağlayacak ve projeniz gerektiriyorsa diğer kütüphaneleri daha kolay öğrenebileceksiniz.

Gereksinimler

Bu eğitime başlamadan önce, gerekli araçlara ve bilgiye sahip olduğunuzdan emin olmak önemlidir. Bu eğitimin önkoşulları aşağıdaki gibidir:

React Temel Bilgiler

Öncelikle, tek sayfa uygulamaları oluşturmak için popüler bir JavaScript kütüphanesi olan React hakkında temel bir anlayışa sahip olmalısınız. JSX (JavaScript XML), bileşenler, durum ve React'teki özellikler gibi kavramlara aşina olmalısınız.

Geliştirme Ortamı

Ayrıca, bilgisayarınızda React uygulamaları geliştirmek için bir geliştirme ortamı kurulu olmalıdır. Bu, bir metin düzenleyici veya Entegre Geliştirme Ortamı (IDE) içerir. Visual Studio Code, Atom veya Sublime Text gibi metin düzenleyiciler iyi seçeneklerdir.

Node.js ve npm

Projemizi ve bağımlılıklarını yönetmek için Node.js ve npm (Node Paket Yöneticisi)'yi kullanacağız. Bilgisayarınızda Node.js'in kurulu olduğundan emin olun. Node.js, sunucularımızda JavaScript çalıştırmamızı sağlayan bir JavaScript çalışma zamanıdır. Kütüphaneleri projeniz için yönetebilmeniz için npm ile birlikte gelir.

Node.js ve npm'in kurulu olup olmadığını şu terminal komutlarını çalıştırarak kontrol edebilirsiniz:

node -v
npm -v
node -v
npm -v
SHELL

Bu komutlar sisteminize kurulu Node.js ve npm'in sürümünü sırasıyla gösterecektir. Eğer kurulmadılarsa veya sürümleriniz eskiyse, en son Uzun Dönem Desteği (LTS) sürümünü resmi indirme sayfasından indirip kurmalısınız.

Adım 1: Projeyi Kurmak

React projemizi kurarak başlayalım. Terminalinizi açın ve projenizi oluşturmak istediğiniz dizine gidin. Yeni bir React uygulaması oluşturmak için aşağıdaki komutu çalıştırın:

npx create-react-app pdf-from-react
npx create-react-app pdf-from-react
SHELL

React'te PDF Dosyası Nasıl Oluşturulur: Şekil 1 - Yukarıdaki komutun yürütülmekte olduğunu gösteren terminal ekran görüntüsü.

Bu komut, temel bir React proje yapısına sahip pdf-from-react adlı yeni bir dizin oluşturacaktır.

Ardından, proje dizinine gidin:

cd pdf-from-react
cd pdf-from-react
SHELL

Şimdi, projeyi kod düzenleyicimizde açabilir ve uygulamaya devam edebiliriz.

Adım 2: Gerekli Bağımlılıkları Eklemek

Öncelikle, gerekli paketleri kurmamız gerekiyor. react, react-dom, @mui/material ve jspdf aşağıdaki terminal komutunu kullanarak yükleyin.

npm install jspdf @mui/material @emotion/react @emotion/styled @mui/icons-material
npm install jspdf @mui/material @emotion/react @emotion/styled @mui/icons-material
SHELL

Adım 3: PDF Oluşturma Özelliği Oluşturmak

Kütüphaneleri İçe Aktarma

Uygulamamız için gerekli bağımlılıkları içe aktararak başlıyoruz. Bunlar, PDF oluşturmak için jsPDF kütüphanesi ve stil düzenleme araçları gibi Material-UI kütüphanesinden çeşitli bileşenleri içerir.

import React, { useState } from "react";
import "./App.css";
import {
  Button,
  TextField,
  Box,
  Container,
  Typography,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  IconButton,
  Snackbar,
  Alert,
} from "@mui/material";
import Grid from "@mui/material/Grid";
import DeleteIcon from "@mui/icons-material/Delete";
import jsPDF from "jspdf";
import { styled } from "@mui/material/styles";
import { tableCellClasses } from "@mui/material/TableCell";
import React, { useState } from "react";
import "./App.css";
import {
  Button,
  TextField,
  Box,
  Container,
  Typography,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  IconButton,
  Snackbar,
  Alert,
} from "@mui/material";
import Grid from "@mui/material/Grid";
import DeleteIcon from "@mui/icons-material/Delete";
import jsPDF from "jspdf";
import { styled } from "@mui/material/styles";
import { tableCellClasses } from "@mui/material/TableCell";
JAVASCRIPT

Stilize Edilmiş Bileşenler Oluşturmak

Uygulamamıza tarayıcılar arası tutarlı davranış eklemek için MUI kütüphanesinden styled aracını kullanarak StyledTableCell ve StyledTableRow oluşturduk.

const StyledTableCell = styled(TableCell)(({ theme }) => ({
  [`&.${tableCellClasses.head}`]: {
    backgroundColor: theme.palette.common.black,
    color: theme.palette.common.white,
  },
  [`&.${tableCellClasses.body}`]: {
    fontSize: 14,
  },
}));

const StyledTableRow = styled(TableRow)(({ theme }) => ({
  "&:nth-of-type(odd)": {
    backgroundColor: theme.palette.action.hover,
  },
  "&:last-child td, &:last-child th": {
    border: 0,
  },
}));
const StyledTableCell = styled(TableCell)(({ theme }) => ({
  [`&.${tableCellClasses.head}`]: {
    backgroundColor: theme.palette.common.black,
    color: theme.palette.common.white,
  },
  [`&.${tableCellClasses.body}`]: {
    fontSize: 14,
  },
}));

const StyledTableRow = styled(TableRow)(({ theme }) => ({
  "&:nth-of-type(odd)": {
    backgroundColor: theme.palette.action.hover,
  },
  "&:last-child td, &:last-child th": {
    border: 0,
  },
}));
JAVASCRIPT

Uygulama Bileşeni Oluşturmak

Uygulamamızın ana bileşeni App bileşenidir. Müşteri verilerini izlemek için customerName ve customerAddress olmak üzere dört durum değişkenimiz var, faturadaki öğelerin listesini izlemek için items ve gerektiğinde hata mesajı görüntülemek için error.

function App() {
  // State variables
  const [customerName, setCustomerName] = useState("");
  const [customerAddress, setCustomerAddress] = useState("");
  const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]);
  const [error, setError] = useState(false);
function App() {
  // State variables
  const [customerName, setCustomerName] = useState("");
  const [customerAddress, setCustomerAddress] = useState("");
  const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]);
  const [error, setError] = useState(false);
JAVASCRIPT

Kullanıcı Girdisi İşleme

Bu kod bloğunda, kullanıcı etkileşimlerini işlemek için fonksiyonlar tanımladık: öğe bilgilerini değiştirme, yeni bir öğe ekleme ve bir öğeyi silme. handleItemChange fonksiyonu, bir kullanıcı bir öğenin özelliklerini değiştirdiğinde bu özellikleri günceller. addItem fonksiyonu listeye yeni bir öğe ekler. deleteItem fonksiyonu, listedeki bir öğeyi kaldırır.

const handleItemChange = (index, event) => {
  let newItems = [...items];
  newItems[index][event.target.name] = event.target.value;
  setItems(newItems);
};

const addItem = () => {
  setItems([...items, { name: "", quantity: "", price: "" }]);
};

const deleteItem = (index) => {
  let newItems = [...items];
  newItems.splice(index, 1);
  setItems(newItems);
};
const handleItemChange = (index, event) => {
  let newItems = [...items];
  newItems[index][event.target.name] = event.target.value;
  setItems(newItems);
};

const addItem = () => {
  setItems([...items, { name: "", quantity: "", price: "" }]);
};

const deleteItem = (index) => {
  let newItems = [...items];
  newItems.splice(index, 1);
  setItems(newItems);
};
JAVASCRIPT

Faturayı Oluşturma

İşte generateInvoice fonksiyon kodu:

// Generate invoice
const generateInvoice = () => {
  // Validate the input fields
  if (
    !customerName ||
    !customerAddress ||
    items.some((item) => !item.name || !item.quantity || !item.price)
  ) {
    setError(true);
    return;
  }

  // Create a new jsPDF instance
  let doc = new jsPDF("p", "pt");

  // Add invoice header
  doc.setFontSize(24);
  doc.text("Invoice", 40, 60);
  doc.setFontSize(10);
  doc.text("Invoice Number: 123456", 40, 90);
  doc.text("Date: " + new Date().toDateString(), 40, 110);
  doc.text(`Customer Name: ${customerName}`, 40, 130);
  doc.text(`Customer Address: ${customerAddress}`, 40, 150);

  // Add items section
  doc.setFontSize(14);
  doc.text("Items:", 40, 200);
  doc.line(40, 210, 550, 210);

  // Add item details
  doc.setFontSize(12);
  let yOffset = 240;
  let total = 0;

  items.forEach((item) => {
    let itemTotal = item.quantity * item.price;
    total += itemTotal;

    doc.text(`Item: ${item.name}`, 40, yOffset);
    doc.text(`Quantity: ${item.quantity}`, 200, yOffset);
    doc.text(`Price: $${item.price}`, 300, yOffset);
    doc.text(`Total: $${itemTotal}`, 400, yOffset);

    yOffset += 20;
  });

  // Add total
  doc.line(40, yOffset, 550, yOffset);
  doc.setFontSize(14);
  doc.text(`Total: $${total}`, 400, yOffset + 30);

  // Save the generated PDF as "invoice.pdf"
  doc.save("invoice.pdf");

  // Reset error state
  setError(false);
};
// Generate invoice
const generateInvoice = () => {
  // Validate the input fields
  if (
    !customerName ||
    !customerAddress ||
    items.some((item) => !item.name || !item.quantity || !item.price)
  ) {
    setError(true);
    return;
  }

  // Create a new jsPDF instance
  let doc = new jsPDF("p", "pt");

  // Add invoice header
  doc.setFontSize(24);
  doc.text("Invoice", 40, 60);
  doc.setFontSize(10);
  doc.text("Invoice Number: 123456", 40, 90);
  doc.text("Date: " + new Date().toDateString(), 40, 110);
  doc.text(`Customer Name: ${customerName}`, 40, 130);
  doc.text(`Customer Address: ${customerAddress}`, 40, 150);

  // Add items section
  doc.setFontSize(14);
  doc.text("Items:", 40, 200);
  doc.line(40, 210, 550, 210);

  // Add item details
  doc.setFontSize(12);
  let yOffset = 240;
  let total = 0;

  items.forEach((item) => {
    let itemTotal = item.quantity * item.price;
    total += itemTotal;

    doc.text(`Item: ${item.name}`, 40, yOffset);
    doc.text(`Quantity: ${item.quantity}`, 200, yOffset);
    doc.text(`Price: $${item.price}`, 300, yOffset);
    doc.text(`Total: $${itemTotal}`, 400, yOffset);

    yOffset += 20;
  });

  // Add total
  doc.line(40, yOffset, 550, yOffset);
  doc.setFontSize(14);
  doc.text(`Total: $${total}`, 400, yOffset + 30);

  // Save the generated PDF as "invoice.pdf"
  doc.save("invoice.pdf");

  // Reset error state
  setError(false);
};
JAVASCRIPT

generateInvoice fonksiyonunda, önce müşteri adı, müşteri adresi ve öğe detaylarının doldurulduğunu sağlamak için giriş alanlarında doğrulama yaparız. Bu alanlardan herhangi biri boşsa, error durumunun true 'ye ayarlanmasını ve erken döndürmeyi sağlarız.

jsPDF 'nın yeni bir örneğini new jsPDF("p", "pt") çağırarak oluşturuyoruz. İlk argüman "p" sayfa yönünün portre olarak belirlendiğini ve ikinci argüman "pt" ölçüm biriminin puanlar olduğunu belirtir.

Ardından, PDF belgimize içerik eklemeye başlıyoruz. doc.setFontSize kullanarak yazı tipi boyutunu ayarlıyoruz ve sayfadaki belirli koordinatlarda metin eklemek için doc.text metodunu kullanıyoruz. Faturanın başlığını, başlığı, fatura numarasını, tarihi, müşteri adını ve müşteri adresini ekliyoruz.

Başlıktan sonra, öğeleri başlıktan ayırmak için doc.line kullanarak yazı tipi boyutunu ayarlayarak ve bir çizgi ekleyerek "Öğeler" bölümünü ekliyoruz. items dizisindeki her bir öğeyi yineleyerek, miktarı fiyatla çarparak her bir öğenin toplam fiyatını hesaplarız. Tüm öğe toplamlarının toplamı ile total değişkenini güncelleriz.

Her öğe için, öğe adı, miktarı, fiyatı ve öğe-toplamını PDF belgesine eklemek için doc.text kullanırız. Her öğe için bir sonraki satıra geçmek amacıyla yOffset değişkenini artırırız. Son olarak, toplamdan öğeleri ayırmak için bir çizgi ekleyip toplam miktarı belgenin sağ alt kısmına eklemek için doc.text kullanırız.

İçerik eklendikten sonra, oluşturulan PDF'i kullanıcı bilgisayarında "invoice.pdf" olarak kaydetmek için doc.save("invoice.pdf") kullanırız. Son olarak, önceki doğrulama hatalarını temizlemek için error durumunu false olarak sıfırlıyoruz.

Adım 4: Kullanıcı Arayüzünü İşleme

return ifadesi, render işlemini yöneten JSX kodunu içerir. Müşteri adı ve adresi için giriş alanları, öğe bilgilerini girmek için bir tablo, öğe eklemek ve faturayı oluşturmak için düğmeler ve doğrulama hatalarını göstermek için bir hata snackbar'ı içerir.

Material-UI kütüphanesindeki Button, TextField, Box, Container, Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, IconButton, Snackbar ve Alert gibi bileşenleri kullanarak temel bileşenler oluşturur. Bu bileşenler, form alanları, tablolar, düğmeler ve hata bildirimleri oluşturmak için kullanılır.

return (
  <Container maxWidth="md">
    <Box sx={{my: 4}}>
      <Typography variant="h3" component="h1" gutterBottom>
        Create Invoice
      </Typography>

      {/* Customer Name and Address fields */}
      <Grid container spacing={3}>
        <Grid item xs={6}>
          <TextField
            label="Customer Name"
            fullWidth
            margin="normal"
            value={customerName}
            onChange={(e) => setCustomerName(e.target.value)}
          />
        </Grid>
        <Grid item xs={6}>
          <TextField
            label="Customer Address"
            fullWidth
            margin="normal"
            value={customerAddress}
            onChange={(e) => setCustomerAddress(e.target.value)}
          />
        </Grid>
      </Grid>

      {/* Items table */}
      <TableContainer component={Paper}>
        <Table sx={{minWidth: 700}} aria-label="invoice table">
          <TableHead>
            <TableRow>
              <StyledTableCell>Item Name</StyledTableCell>
              <StyledTableCell align="left">Quantity</StyledTableCell>
              <StyledTableCell align="left">Price</StyledTableCell>
              <StyledTableCell align="left">Action</StyledTableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {items.map((item, index) => (
              <StyledTableRow key={index}>
                <StyledTableCell component="th" scope="row">
                  <TextField
                    fullWidth
                    value={item.name}
                    onChange={(event) => handleItemChange(index, event)}
                    name="name"
                  />
                </StyledTableCell>
                <StyledTableCell align="right">
                  <TextField
                    fullWidth
                    value={item.quantity}
                    onChange={(event) => handleItemChange(index, event)}
                    name="quantity"
                  />
                </StyledTableCell>
                <StyledTableCell align="right">
                  <TextField
                    fullWidth
                    value={item.price}
                    onChange={(event) => handleItemChange(index, event)}
                    name="price"
                  />
                </StyledTableCell>
                <StyledTableCell align="right">
                  <IconButton onClick={() => deleteItem(index)}>
                    <DeleteIcon />
                  </IconButton>
                </StyledTableCell>
              </StyledTableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>

      {/* Buttons */}
      <Box mt={2} display="flex" gap={2}>
        <Button variant="contained" onClick={addItem}>
          Add Item
        </Button>
        <Button variant="outlined" color="success" onClick={generateInvoice}>
          Generate Invoice
        </Button>
      </Box>
    </Box>

    {/* Error Snackbar */}
    <Snackbar
      open={error}
      autoHideDuration={6000}
      onClose={() => setError(false)}
      anchorOrigin={{vertical: "top", horizontal: "right"}}
    >
      <Alert onClose={() => setError(false)} severity="error">
        Please fill in all required fields.
      </Alert>
    </Snackbar>
  </Container>
);
return (
  <Container maxWidth="md">
    <Box sx={{my: 4}}>
      <Typography variant="h3" component="h1" gutterBottom>
        Create Invoice
      </Typography>

      {/* Customer Name and Address fields */}
      <Grid container spacing={3}>
        <Grid item xs={6}>
          <TextField
            label="Customer Name"
            fullWidth
            margin="normal"
            value={customerName}
            onChange={(e) => setCustomerName(e.target.value)}
          />
        </Grid>
        <Grid item xs={6}>
          <TextField
            label="Customer Address"
            fullWidth
            margin="normal"
            value={customerAddress}
            onChange={(e) => setCustomerAddress(e.target.value)}
          />
        </Grid>
      </Grid>

      {/* Items table */}
      <TableContainer component={Paper}>
        <Table sx={{minWidth: 700}} aria-label="invoice table">
          <TableHead>
            <TableRow>
              <StyledTableCell>Item Name</StyledTableCell>
              <StyledTableCell align="left">Quantity</StyledTableCell>
              <StyledTableCell align="left">Price</StyledTableCell>
              <StyledTableCell align="left">Action</StyledTableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {items.map((item, index) => (
              <StyledTableRow key={index}>
                <StyledTableCell component="th" scope="row">
                  <TextField
                    fullWidth
                    value={item.name}
                    onChange={(event) => handleItemChange(index, event)}
                    name="name"
                  />
                </StyledTableCell>
                <StyledTableCell align="right">
                  <TextField
                    fullWidth
                    value={item.quantity}
                    onChange={(event) => handleItemChange(index, event)}
                    name="quantity"
                  />
                </StyledTableCell>
                <StyledTableCell align="right">
                  <TextField
                    fullWidth
                    value={item.price}
                    onChange={(event) => handleItemChange(index, event)}
                    name="price"
                  />
                </StyledTableCell>
                <StyledTableCell align="right">
                  <IconButton onClick={() => deleteItem(index)}>
                    <DeleteIcon />
                  </IconButton>
                </StyledTableCell>
              </StyledTableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>

      {/* Buttons */}
      <Box mt={2} display="flex" gap={2}>
        <Button variant="contained" onClick={addItem}>
          Add Item
        </Button>
        <Button variant="outlined" color="success" onClick={generateInvoice}>
          Generate Invoice
        </Button>
      </Box>
    </Box>

    {/* Error Snackbar */}
    <Snackbar
      open={error}
      autoHideDuration={6000}
      onClose={() => setError(false)}
      anchorOrigin={{vertical: "top", horizontal: "right"}}
    >
      <Alert onClose={() => setError(false)} severity="error">
        Please fill in all required fields.
      </Alert>
    </Snackbar>
  </Container>
);
JAVASCRIPT

Tam App.js ve App.css Kodu

Projenize yapıştırabileceğiniz tam App.js kodu burada:

import React, { useState } from "react";
import "./App.css";
import {
  Button,
  TextField,
  Box,
  Container,
  Typography,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  IconButton,
  Snackbar,
  Alert,
} from "@mui/material";
import Grid from "@mui/material/Grid";
import DeleteIcon from "@mui/icons-material/Delete";
import jsPDF from "jspdf";
import { styled } from "@mui/material/styles";
import { tableCellClasses } from "@mui/material/TableCell";

const StyledTableCell = styled(TableCell)(({ theme }) => ({
  [`&.${tableCellClasses.head}`]: {
    backgroundColor: theme.palette.common.black,
    color: theme.palette.common.white,
  },
  [`&.${tableCellClasses.body}`]: {
    fontSize: 14,
  },
}));

const StyledTableRow = styled(TableRow)(({ theme }) => ({
  "&:nth-of-type(odd)": {
    backgroundColor: theme.palette.action.hover,
  },
  "&:last-child td, &:last-child th": {
    border: 0,
  },
}));

function App() {
  // State variables
  const [customerName, setCustomerName] = useState("");
  const [customerAddress, setCustomerAddress] = useState("");
  const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]);
  const [error, setError] = useState(false);

  // Event handler for item changes
  const handleItemChange = (index, event) => {
    let newItems = [...items];
    newItems[index][event.target.name] = event.target.value;
    setItems(newItems);
  };

  // Add new item to the list
  const addItem = () => {
    setItems([...items, { name: "", quantity: "", price: "" }]);
  };

  // Delete an item from the list
  const deleteItem = (index) => {
    let newItems = [...items];
    newItems.splice(index, 1);
    setItems(newItems);
  };

  // Generate invoice
  const generateInvoice = () => {
    // Validate the input fields
    if (
      !customerName ||
      !customerAddress ||
      items.some((item) => !item.name || !item.quantity || !item.price)
    ) {
      setError(true);
      return;
    }

    // Create a new jsPDF instance
    let doc = new jsPDF("p", "pt");

    // Add invoice header
    doc.setFontSize(24);
    doc.text("Invoice", 40, 60);
    doc.setFontSize(10);
    doc.text("Invoice Number: 123456", 40, 90);
    doc.text("Date: " + new Date().toDateString(), 40, 110);
    doc.text(`Customer Name: ${customerName}`, 40, 130);
    doc.text(`Customer Address: ${customerAddress}`, 40, 150);

    // Add items section
    doc.setFontSize(14);
    doc.text("Items:", 40, 200);
    doc.line(40, 210, 550, 210);

    // Add item details
    doc.setFontSize(12);
    let yOffset = 240;
    let total = 0;

    items.forEach((item) => {
      let itemTotal = item.quantity * item.price;
      total += itemTotal;

      doc.text(`Item: ${item.name}`, 40, yOffset);
      doc.text(`Quantity: ${item.quantity}`, 200, yOffset);
      doc.text(`Price: $${item.price}`, 300, yOffset);
      doc.text(`Total: $${itemTotal}`, 400, yOffset);

      yOffset += 20;
    });

    // Add total
    doc.line(40, yOffset, 550, yOffset);
    doc.setFontSize(14);
    doc.text(`Total: $${total}`, 400, yOffset + 30);

    // Save the generated PDF as "invoice.pdf"
    doc.save("invoice.pdf");

    // Reset error state
    setError(false);
  };

  return (
    <Container maxWidth="md">
      <Box sx={{my: 4}}>
        <Typography variant="h3" component="h1" gutterBottom>
          Create Invoice
        </Typography>

        {/* Customer Name and Address fields */}
        <Grid container spacing={3}>
          <Grid item xs={6}>
            <TextField
              label="Customer Name"
              fullWidth
              margin="normal"
              value={customerName}
              onChange={(e) => setCustomerName(e.target.value)}
            />
          </Grid>
          <Grid item xs={6}>
            <TextField
              label="Customer Address"
              fullWidth
              margin="normal"
              value={customerAddress}
              onChange={(e) => setCustomerAddress(e.target.value)}
            />
          </Grid>
        </Grid>

        {/* Items table */}
        <TableContainer component={Paper}>
          <Table sx={{minWidth: 700}} aria-label="invoice table">
            <TableHead>
              <TableRow>
                <StyledTableCell>Item Name</StyledTableCell>
                <StyledTableCell align="left">Quantity</StyledTableCell>
                <StyledTableCell align="left">Price</StyledTableCell>
                <StyledTableCell align="left">Action</StyledTableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {items.map((item, index) => (
                <StyledTableRow key={index}>
                  <StyledTableCell component="th" scope="row">
                    <TextField
                      fullWidth
                      value={item.name}
                      onChange={(event) => handleItemChange(index, event)}
                      name="name"
                    />
                  </StyledTableCell>
                  <StyledTableCell align="right">
                    <TextField
                      fullWidth
                      value={item.quantity}
                      onChange={(event) => handleItemChange(index, event)}
                      name="quantity"
                    />
                  </StyledTableCell>
                  <StyledTableCell align="right">
                    <TextField
                      fullWidth
                      value={item.price}
                      onChange={(event) => handleItemChange(index, event)}
                      name="price"
                    />
                  </StyledTableCell>
                  <StyledTableCell align="right">
                    <IconButton onClick={() => deleteItem(index)}>
                      <DeleteIcon />
                    </IconButton>
                  </StyledTableCell>
                </StyledTableRow>
              ))}
            </TableBody>
          </Table>
        </TableContainer>

        {/* Buttons */}
        <Box mt={2} display="flex" gap={2}>
          <Button variant="contained" onClick={addItem}>
            Add Item
          </Button>
          <Button variant="outlined" color="success" onClick={generateInvoice}>
            Generate Invoice
          </Button>
        </Box>
      </Box>

      {/* Error Snackbar */}
      <Snackbar
        open={error}
        autoHideDuration={6000}
        onClose={() => setError(false)}
        anchorOrigin={{vertical: "top", horizontal: "right"}}
      >
        <Alert onClose={() => setError(false)} severity="error">
          Please fill in all required fields.
        </Alert>
      </Snackbar>
    </Container>
  );
}
export default App;
import React, { useState } from "react";
import "./App.css";
import {
  Button,
  TextField,
  Box,
  Container,
  Typography,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  IconButton,
  Snackbar,
  Alert,
} from "@mui/material";
import Grid from "@mui/material/Grid";
import DeleteIcon from "@mui/icons-material/Delete";
import jsPDF from "jspdf";
import { styled } from "@mui/material/styles";
import { tableCellClasses } from "@mui/material/TableCell";

const StyledTableCell = styled(TableCell)(({ theme }) => ({
  [`&.${tableCellClasses.head}`]: {
    backgroundColor: theme.palette.common.black,
    color: theme.palette.common.white,
  },
  [`&.${tableCellClasses.body}`]: {
    fontSize: 14,
  },
}));

const StyledTableRow = styled(TableRow)(({ theme }) => ({
  "&:nth-of-type(odd)": {
    backgroundColor: theme.palette.action.hover,
  },
  "&:last-child td, &:last-child th": {
    border: 0,
  },
}));

function App() {
  // State variables
  const [customerName, setCustomerName] = useState("");
  const [customerAddress, setCustomerAddress] = useState("");
  const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]);
  const [error, setError] = useState(false);

  // Event handler for item changes
  const handleItemChange = (index, event) => {
    let newItems = [...items];
    newItems[index][event.target.name] = event.target.value;
    setItems(newItems);
  };

  // Add new item to the list
  const addItem = () => {
    setItems([...items, { name: "", quantity: "", price: "" }]);
  };

  // Delete an item from the list
  const deleteItem = (index) => {
    let newItems = [...items];
    newItems.splice(index, 1);
    setItems(newItems);
  };

  // Generate invoice
  const generateInvoice = () => {
    // Validate the input fields
    if (
      !customerName ||
      !customerAddress ||
      items.some((item) => !item.name || !item.quantity || !item.price)
    ) {
      setError(true);
      return;
    }

    // Create a new jsPDF instance
    let doc = new jsPDF("p", "pt");

    // Add invoice header
    doc.setFontSize(24);
    doc.text("Invoice", 40, 60);
    doc.setFontSize(10);
    doc.text("Invoice Number: 123456", 40, 90);
    doc.text("Date: " + new Date().toDateString(), 40, 110);
    doc.text(`Customer Name: ${customerName}`, 40, 130);
    doc.text(`Customer Address: ${customerAddress}`, 40, 150);

    // Add items section
    doc.setFontSize(14);
    doc.text("Items:", 40, 200);
    doc.line(40, 210, 550, 210);

    // Add item details
    doc.setFontSize(12);
    let yOffset = 240;
    let total = 0;

    items.forEach((item) => {
      let itemTotal = item.quantity * item.price;
      total += itemTotal;

      doc.text(`Item: ${item.name}`, 40, yOffset);
      doc.text(`Quantity: ${item.quantity}`, 200, yOffset);
      doc.text(`Price: $${item.price}`, 300, yOffset);
      doc.text(`Total: $${itemTotal}`, 400, yOffset);

      yOffset += 20;
    });

    // Add total
    doc.line(40, yOffset, 550, yOffset);
    doc.setFontSize(14);
    doc.text(`Total: $${total}`, 400, yOffset + 30);

    // Save the generated PDF as "invoice.pdf"
    doc.save("invoice.pdf");

    // Reset error state
    setError(false);
  };

  return (
    <Container maxWidth="md">
      <Box sx={{my: 4}}>
        <Typography variant="h3" component="h1" gutterBottom>
          Create Invoice
        </Typography>

        {/* Customer Name and Address fields */}
        <Grid container spacing={3}>
          <Grid item xs={6}>
            <TextField
              label="Customer Name"
              fullWidth
              margin="normal"
              value={customerName}
              onChange={(e) => setCustomerName(e.target.value)}
            />
          </Grid>
          <Grid item xs={6}>
            <TextField
              label="Customer Address"
              fullWidth
              margin="normal"
              value={customerAddress}
              onChange={(e) => setCustomerAddress(e.target.value)}
            />
          </Grid>
        </Grid>

        {/* Items table */}
        <TableContainer component={Paper}>
          <Table sx={{minWidth: 700}} aria-label="invoice table">
            <TableHead>
              <TableRow>
                <StyledTableCell>Item Name</StyledTableCell>
                <StyledTableCell align="left">Quantity</StyledTableCell>
                <StyledTableCell align="left">Price</StyledTableCell>
                <StyledTableCell align="left">Action</StyledTableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {items.map((item, index) => (
                <StyledTableRow key={index}>
                  <StyledTableCell component="th" scope="row">
                    <TextField
                      fullWidth
                      value={item.name}
                      onChange={(event) => handleItemChange(index, event)}
                      name="name"
                    />
                  </StyledTableCell>
                  <StyledTableCell align="right">
                    <TextField
                      fullWidth
                      value={item.quantity}
                      onChange={(event) => handleItemChange(index, event)}
                      name="quantity"
                    />
                  </StyledTableCell>
                  <StyledTableCell align="right">
                    <TextField
                      fullWidth
                      value={item.price}
                      onChange={(event) => handleItemChange(index, event)}
                      name="price"
                    />
                  </StyledTableCell>
                  <StyledTableCell align="right">
                    <IconButton onClick={() => deleteItem(index)}>
                      <DeleteIcon />
                    </IconButton>
                  </StyledTableCell>
                </StyledTableRow>
              ))}
            </TableBody>
          </Table>
        </TableContainer>

        {/* Buttons */}
        <Box mt={2} display="flex" gap={2}>
          <Button variant="contained" onClick={addItem}>
            Add Item
          </Button>
          <Button variant="outlined" color="success" onClick={generateInvoice}>
            Generate Invoice
          </Button>
        </Box>
      </Box>

      {/* Error Snackbar */}
      <Snackbar
        open={error}
        autoHideDuration={6000}
        onClose={() => setError(false)}
        anchorOrigin={{vertical: "top", horizontal: "right"}}
      >
        <Alert onClose={() => setError(false)} severity="error">
          Please fill in all required fields.
        </Alert>
      </Snackbar>
    </Container>
  );
}
export default App;
JAVASCRIPT

İşte App.css kodu:

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap');
.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-weight: bold;
  /* This is the weight for bold in Poppins */
  color: #FF6347;
  /* This is the color Tomato. Replace with your preferred color */
}

body {
  font-family: 'Poppins', sans-serif;
  background-color: #E9F8F4;
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

Adım 5: Uygulamayı Test Etmek

PDF oluşturma özelliğini test etmek için terminalde aşağıdaki komutu çalıştırın:

npm start
npm start
SHELL

Bu, geliştirme sunucusunu başlatacak ve uygulamayı tarayıcınızda http://localhost:3000 adresinde görüntüleyebileceksiniz.

React'te PDF Dosyası Nasıl Oluşturulur - Şekil 2: Varsayılan, doldurulmamış alanlarla tamamlanmış fatura uygulaması.

Giriş alanlarına müşteri adı, adresi ve öğe bilgilerini doldurun ve "Fatura Oluştur" düğmesine tıklayın. PDF dosyası bilgisayarınıza indirilecek ve üretilen faturanın tam sayfa görünümünü görmek için açabilirsiniz.

React'te PDF Dosyası Nasıl Oluşturulur - Şekil 3: Üç satırlı öğele doldurulmuş, farklı öğeler, miktarlar ve fiyatlar ile uygulama.

"Fatura Oluştur" düğmesine tıkladığınızda, PDF dosyası oluşturulacaktır.

React'te PDF Dosyası Nasıl Oluşturulur - Şekil 4: Oluşturulan PDF.

Herhangi bir boş alan ile PDF oluşturmaya çalışırsanız, sağ üst köşede bir hata mesajı gösterilecektir.

React'te PDF Dosyası Nasıl Oluşturulur - Şekil 5: Tüm alanlar doldurulmadığı için bir hata mesajı gösterilir.

IronPDF - Node.js PDF Kütüphanesi

IronPDF Node.js için, doğruluk, kullanım kolaylığı ve hız açısından mükemmelleşmiş kapsamlı bir Node.js PDF kütüphanesidir. React'ta HTML, URL'ler ve görüntülerden doğrudan PDF'ler oluşturma, düzenleme ve biçimlendirme için geniş bir dizi özellik sunar. IronPDF, Windows, MacOS, Linux, Docker ve Azure ve AWS gibi bulut platformları dahil olmak üzere çeşitli platformlar için destek sunarak platformlar arası uyumluluk sağlar. Kullanıcı dostu API'si geliştiricilerin PDF oluşturma ve işleme işlemlerini Node.js projelerine hızlıca entegre etmelerine olanak tanır.

IronPDF Node.js'nin dikkat çekici özellikleri arasında: piksel mükemmelliğinde render, kapsamlı biçimlendirme seçenekleri ve PDF'leri birleştirme ve bölme, açıklama ekleme ve PDF formları oluşturma gibi gelişmiş düzenleme yetenekleri yer alır.

İşte bir HTML Dosyası, HTML Dizesi ve bir URL'den PDF belgesi oluşturmanın bir örneği:

import { PdfDocument } from "@ironsoftware/ironpdf";

(async () => {
  const pdfFromUrl = await PdfDocument.fromUrl("https://getbootstrap.com/");
  await pdfFromUrl.saveAs("website.pdf");

  const pdfFromHtmlFile = await PdfDocument.fromHtml("design.html");
  await pdfFromHtmlFile.saveAs("markup.pdf");

  const pdfFromHtmlString = await PdfDocument.fromHtml("<p>Hello World</p>");
  await pdfFromHtmlString.saveAs("markup_with_assets.pdf");
})();
import { PdfDocument } from "@ironsoftware/ironpdf";

(async () => {
  const pdfFromUrl = await PdfDocument.fromUrl("https://getbootstrap.com/");
  await pdfFromUrl.saveAs("website.pdf");

  const pdfFromHtmlFile = await PdfDocument.fromHtml("design.html");
  await pdfFromHtmlFile.saveAs("markup.pdf");

  const pdfFromHtmlString = await PdfDocument.fromHtml("<p>Hello World</p>");
  await pdfFromHtmlString.saveAs("markup_with_assets.pdf");
})();
JAVASCRIPT

PDF ile ilgili görevlerle ilgili daha fazla kod örneği için lütfen bu IronPDF kod örnekleri sayfasını ziyaret edin.

Sonuç

Sonuç olarak, bir React uygulamasında PDF oluşturmak göz korkutucu olmak zorunda değildir. Doğru araçlarla ve net bir anlayışla güzel, iyi yapılandırılmış PDF belgelerini zahmetsizce oluşturabilirsiniz. jsPDF, pdfmake ve React-PDF gibi her birinin kendi güçlü yönleri ve benzersiz özellikleri olan çeşitli kütüphaneleri keşfettik.

IronPDF'nin JavaScript'te çerçeveler ve kütüphanelerle entegrasyon süreci, mükemmel belgelendirme ve duyarlı teknik desteği, geliştiricilerin hızlı ve kolay bir şekilde profesyonel düzeyde PDF'ler oluşturmasına olanak tanır, bu da Node.js uygulamalarında en iyi seçimlerden biri haline getirir.

IronPDF, tüm işlevselliğinin ücretsiz deneme sürümünü sunar. Ayrıca C# .NET, Java ve Python gibi diğer diller için de mevcuttur. Daha fazla ayrıntı için IronPDF web sitesini ziyaret edin.

Darrius Serrant
Tam Yığın Yazılım Mühendisi (WebOps)

Darrius Serrant, Miami Üniversitesi'nden Bilgisayar Bilimi alanında Lisans Derecesine sahip ve Iron Software'de Tam Yığın WebOps Pazarlama Mühendisi olarak çalışıyor. Genç yaşlardan itibaren kodlamaya çekildi, bilgisayar bilimi hem gizemli hem de erişilebilir olarak görüldü ve bu özellik, yaratıcılık ...

Daha Fazla Oku

Iron Destek Ekibi

Haftada 5 gün, 24 saat çevrimiçiyiz.
Sohbet
E-posta
Beni Ara