This is a React application that generates PDF documents about real estate and allows sharing them via social media and messaging platforms.
- Dynamic PDF generation with html2pdf.js
- PDF sharing via Facebook, VK, Telegram, WhatsApp, and Email
- Integrated server for PDF storage and sharing
- Automatic PDF download functionality
- Custom PDF content with optional logo and description
This project has both the React frontend and Express backend in a single repository:
react-pdf-test/
├── node_modules/
├── public/
├── server/
│ ├── logs/
│ └── uploads/
├── src/
└── package.json
This application has a client-server architecture with both components integrated into a single repository:
- Location:
/srcdirectory - Technology: React 19.1
- Responsibility: UI and PDF generation in the browser
- Default Port: 3000 (development mode)
Settings:
# .env or .env.development
REACT_APP_PORT=3000 # React development server port
- Location:
/serverdirectory - Technology: Express.js
- Responsibility: File uploads, storage, and serving
- Default Port: 3001
Settings:
# .env
PORT=3001 # Express server port
SERVER_URL=http://localhost:3001 # Public URL for file access
When you run npm run dev, two processes are started concurrently:
-
Express Server (
npm run server):- Loads environment variables from
.envusing dotenv - Sets up routes for file uploads, downloads, and API endpoints
- Creates logs and uploads directories if they don't exist
- Binds to PORT from environment variables (defaults to 3001)
- Loads environment variables from
-
React Development Server (
npm run start):- Started by react-scripts
- Serves the React application with hot reloading
- Also reads from
.envfile, particularly looking for PORT - Defaults to port 3000 if not specified
Settings:
// package.json scripts
"scripts": {
"start": "react-scripts start",
"server": "node server/index.js",
"dev": "concurrently \"npm run server\" \"npm run start\"",
"dev:local": "cross-env NODE_ENV=development concurrently \"npm run server\" \"npm run start\""
}Important: To avoid port conflicts, use different ports for React and Express:
# For Express (.env)
PORT=3001
SERVER_URL=http://localhost:3001
# For React (.env.development)
PORT=3000
If both servers try to use the same port (e.g., both reading PORT=3003 from .env), you'll get the error: "Something is already running on port 3003".
-
User Interaction:
- User views the application at http://localhost:3000
- Clicks "Скачать PDF о недвижимости" button
-
PDF Generation on Client:
- Frontend uses html2pdf.js to generate PDF in the browser
- Converts the HTML content to a PDF blob
- Downloads the PDF to the user's device
Settings:
// PDF generation options (App.js) const options = { margin: 10, filename: 'nedvizhimost-document.pdf', image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2, useCORS: true, letterRendering: true }, jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } };
-
PDF Upload to Server:
- The PDF blob is sent to the server via a POST request to
/upload - Server saves the file to
/server/uploads/directory - Server returns a URL to the saved file
Settings:
// Server file upload configuration (server/index.js) const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, uploadDir); }, filename: function (req, file, cb) { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); cb(null, uniqueSuffix + '-' + file.originalname); } });
- The PDF blob is sent to the server via a POST request to
-
File Serving:
- Files are stored in
/server/uploads/ - Server provides two endpoints:
/uploads/:filename- for viewing files in browser/download/:filename- for forcing download
Settings:
// View file configuration app.use('/uploads', express.static(uploadDir, { setHeaders: function (res, path) { if (path.endsWith('.pdf')) { res.set('Content-Type', 'application/pdf'); } } })); // Download file configuration app.get('/download/:filename', (req, res) => { // Force download with Content-Disposition header res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); res.setHeader('Content-Type', 'application/pdf'); });
- Files are stored in
In production mode (npm run build && npm run server):
- React app is compiled to static files in
/build - Express server serves these static files alongside API endpoints
- Everything runs through a single server on a single port
Settings:
# Production environment (.env)
NODE_ENV=production
PORT=3001 # or your preferred port
SERVER_URL=https://yourdomain.com # Use HTTPS in production
- Install dependencies:
npm install
- Start both the frontend and backend servers together:
npm run dev
This will:
- Start the React development server on port 3000
- Start the Express backend server on port 3001
- Run both servers concurrently
- For production:
npm run build
NODE_ENV=production npm run server
This will:
- Build the React app
- Serve the static React app through the Express server
- Handle both the frontend and API requests from a single server
The application creates PDF documents using html2pdf.js. When you click "Скачать PDF", the app:
- Generates the PDF document
- Downloads it to your device
- Uploads it to the server for sharing
The application allows customizing the PDF content with:
- Test Logo: When checked, adds a sample logo to the PDF document
- Test Description: When checked, adds a sample descriptive text to the PDF document
These options can be toggled via checkboxes in the user interface before generating the PDF.
Generated PDFs can be shared via:
- VK
- Telegram
The PDF is uploaded to the server, which provides a permanent URL for sharing.
The React app is in the src/ directory with components for generating and sharing PDFs.
The Express server is in the server/ directory:
server/index.js: Main server file with API endpointsserver/logs/: Directory for server logsserver/uploads/: Directory for storing uploaded PDFs
POST /upload: Upload a PDF fileGET /uploads/:filename: View a PDF file in the browserGET /download/:filename: Download a PDF file directlyGET /check-file/:filename: Verify if a file existsGET /api: Check server status and list existing files
You can customize the PDF content by modifying the template in App.js. The sharing functionality can be extended with additional platforms as needed.
- For production environments, implement proper authentication and authorization
- Set file size limits to prevent abuse
- Consider using HTTPS for secure file transfers
- Implement rate limiting to prevent DoS attacks
This application uses environment variables for configuration.
Create a .env file in the root directory with the following variables:
# Server configuration
SERVER_URL=http://104.36.85.100:3000
PORT=3001
# For production, use HTTPS (uncomment when you have a certificate)
# SERVER_URL=https://104.36.85.100:3000
# HTTPS=true
# Add any other environment variables your app needs here
NODE_ENV=production
For local development, create a .env.development file or update your .env file with:
# Development environment configuration
SERVER_URL=http://localhost:3001
PORT=3001
# React development server port
REACT_APP_PORT=3000
# Other development settings
NODE_ENV=development
# PDF upload path (relative to server directory)
UPLOAD_DIR=uploads
When running in development mode, either set the NODE_ENV manually:
# For Windows
set NODE_ENV=development && npm run dev
# For Linux/Mac
NODE_ENV=development npm run devOr use the development script in package.json:
"scripts": {
"dev": "NODE_ENV=development concurrently \"npm run server\" \"npm run start\""
}The application will use these values to configure the server. Make sure to adjust the SERVER_URL to match your domain or IP address.
The server is configured to handle PDF files in two ways:
-
View PDFs in the browser:
- URL pattern:
/uploads/:filename - Content-Type: application/pdf
- Example:
http://yourdomain.com:3001/uploads/document.pdf
- URL pattern:
-
Force download of PDFs:
- URL pattern:
/download/:filename - Content-Disposition: attachment
- Example:
http://yourdomain.com:3001/download/document.pdf
- URL pattern:
When sharing PDFs, you can choose either URL format depending on whether you want recipients to view the PDF in their browser or download it directly.
To ensure the server can create and serve PDF files, set proper permissions on the uploads directory:
# Navigate to your application directory
cd /path/to/your/app
# Create the uploads directory if it doesn't exist
mkdir -p server/uploads
# Set proper permissions (replace www-data with your web server user)
sudo chown -R www-data:www-data server/uploads
# Set directory permissions to 755 (rwxr-xr-x)
sudo chmod -R 755 server/uploadsThe error message blob:http://104.36.85.100:3000/f85c0748-b886-417b-93ec-a713bd592969 was loaded over an insecure connection indicates a security issue with loading blob URLs over HTTP instead of HTTPS.
- Set up HTTPS on your server using a valid SSL certificate:
# Install certbot for Let's Encrypt SSL
sudo apt-get update
sudo apt-get install certbot
# Get a certificate for your domain
sudo certbot certonly --standalone -d yourdomain.com
# Configure your Node.js server to use HTTPS- Update your server code to use HTTPS:
const https = require('https');
const fs = require('fs');
const app = express();
// Your existing Express setup...
// HTTPS configuration
const httpsOptions = {
key: fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/fullchain.pem')
};
// Create HTTPS server
https.createServer(httpsOptions, app).listen(3001, () => {
console.log('HTTPS Server running on port 3001');
});- Update your environment variables:
# Set the server URL to use HTTPS
SERVER_URL=https://yourdomain.com:3001
The server includes enhanced logging that will help diagnose any file permission issues:
-
Server logs are saved to:
server/logs/server.log- General server logsserver/logs/error.log- Error logs
-
Diagnostic information is logged on server startup:
- Current directory
- Upload directory location and permissions
- File system access tests
- Existing files in uploads directory
-
Each upload operation logs:
- Incoming file details
- File path, size, and permissions
- All files in the directory after upload
- Any errors encountered during the process
If the server has trouble creating PDF files, check the diagnostic information in the logs:
# View the server logs
cat server/logs/server.log
# Check for errors
cat server/logs/error.log
# Check directory permissions
ls -la server/uploadsThe server has additional endpoints to help with troubleshooting:
/api- Check server status and see all files in the uploads directory/check-file/:filename- Verify if a specific file exists on the server
Example usage:
GET http://yourdomain.com:3001/api
GET http://yourdomain.com:3001/check-file/1621345678-987654321-nedvizhimost-document.pdf
This project was bootstrapped with Create React App.
In the project directory, you can run:
Runs the app in the development mode.
Open http://localhost:3000 to view it in your browser.
The page will reload when you make changes.
You may also see any lint errors in the console.
Launches the test runner in the interactive watch mode.
See the section about running tests for more information.
Builds the app for production to the build folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed!
See the section about deployment for more information.
Note: this is a one-way operation. Once you eject, you can't go back!
If you aren't satisfied with the build tool and configuration choices, you can eject at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except eject will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
You don't have to ever use eject. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
You can learn more in the Create React App documentation.
To learn React, check out the React documentation.
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
For development mode with both React and Express servers running, create a .env file in the root directory with the following variables:
# Express server configuration
PORT=3001
REACT_APP_SERVER_URL=http://localhost:3001
NODE_ENV=development
UPLOAD_DIR=uploads
This configuration ensures:
- Express API server runs on port 3001
- React development server runs on port 3000 (default React port)
- React app uses the correct server URL for API requests
- Both servers run in development mode
If you encounter connectivity issues between the React app and Express server, check that:
- The React app is correctly using
process.env.REACT_APP_SERVER_URLfor API calls - No hardcoded URLs exist in the codebase (especially in App.js)
- The Express server is running on the expected port
Remember that in React, only environment variables prefixed with REACT_APP_ are available to the client-side code.