QR Type: vCard
Relevant source files
The following files were used as context for generating this wiki page:The vCard QR type feature allows users to generate a QR code that functions as an electronic business card. When scanned, it provides contact information that can be directly imported into a device's address book. The implementation supports a comprehensive set of contact details, including full name, separate first/last names, phone number, email address, organization, and a personal website.
The system is designed to be robust, incorporating input validation for fields like email, phone, and URL, as well as proper data escaping to handle special characters, ensuring the generated vCard is compliant with the vCard 3.0 standard and scannable by most devices.
Sources: README.md, src/App.jsx:35, src/App.jsx:85-101
UI and State Management
When a user selects "vCard" from the QR type dropdown, the UI dynamically renders a set of input fields tailored for contact information. These inputs are managed by the main App component's state.
Sources: src/App.jsx:701-708, src/App.jsx:818-888
State Representation
The contact details for the vCard are stored within the qrData state object. The following table maps the state properties to their corresponding UI input fields.
| State Property | UI Input Field Label | Description |
|---|---|---|
name | Họ tên đầy đủ | The full name to be displayed in the contact card. |
lastName | Họ | The contact's last name. |
firstName | Tên đệm & Tên | The contact's first and middle names. |
phone | Số điện thoại | The contact's cellular phone number. |
email | Email | The contact's primary email address. |
org | Công ty | The organization or company the contact belongs to. |
vcardUrl | Website | A URL for the contact's personal or company website. |
Sources: src/App.jsx:304-315, src/App.jsx:818-888
The diagram below illustrates the flow from user input to state update for the vCard feature.
This diagram shows how user interactions with the vCard form trigger state updates within the App component.
Sources: src/App.jsx:317, src/App.jsx:702-708
vCard Generation Logic
The core logic for creating the vCard string is encapsulated within the generateQRContent function. When the QR type is vcard, this function assembles a multi-line string formatted according to the vCard version 3.0 specification.
Sources: src/App.jsx:85-101, src/App.test.js:65-83
Data Flow
The generation process follows these steps:
- Retrieve Data: Accesses the vCard-related properties from the
qrDatastate object. - Name Parsing: If
lastNameandfirstNameare not explicitly provided, it attempts to parse thenamefield. The last word is treated as the last name, and the preceding words as the first name. - Escape Data: Each data field is passed through the
escVCARDhelper function to escape special characters like semicolons, commas, and backslashes. Newlines are replaced with\n. - Assemble String: Constructs an array of lines, starting with
BEGIN:VCARDandVERSION:3.0. - Add Fields: Conditionally adds lines for
TEL,EMAIL,ORG, andURLonly if the corresponding data exists. - Finalize: Appends
END:VCARDand joins all lines with a carriage return and line feed (\r\n) separator.
This data flow is visualized in the following diagram:
Sources: src/App.jsx:85-101, src/App.test.js:65-83
Code Implementation
The VCARD case within generateQRContent demonstrates this logic.
// File: src/App.jsx:85-101
case QR_TYPES.VCARD: {
const name = data.name || '';
let lastName = data.lastName || '';
let firstName = data.firstName || '';
if (!lastName && !firstName && name) {
const seg = name.trim().split(/\s+/);
if (seg.length > 1) {
lastName = seg[0];
firstName = seg.slice(1).join(' ');
} else {
firstName = name;
}
}
const lines = [
'BEGIN:VCARD',
'VERSION:3.0',
`FN:${escVCARD(name)}`,
`N:${escVCARD(lastName)};${escVCARD(firstName)};;;`,
];
if (data.phone) lines.push(`TEL;TYPE=CELL:${escVCARD(data.phone)}`);
if (data.email) lines.push(`EMAIL;TYPE=INTERNET:${escVCARD(data.email)}`);
if (data.org) lines.push(`ORG:${escVCARD(data.org)}`);
if (data.vcardUrl) lines.push(`URL:${escVCARD(data.vcardUrl)}`);
lines.push('END:VCARD');
return lines.join('\r\n');
}
Sources: src/App.jsx:85-101
The escVCARD helper function is critical for data integrity.
// File: src/App.jsx:45
const escVCARD = (s = '') => s.replace(/([\\;,])/g, '\\$1').replace(/\n/g, '\\n');
Sources: src/App.jsx:45, src/App.test.js:15
Input Validation
To ensure data quality and prevent errors, the application performs real-time validation on several vCard fields. This logic resides in a useEffect hook that observes changes to qrType and qrData.
Sources: src/App.jsx:321-339
Validation Rules
The following validation rules are applied to the vCard inputs:
| Field | Validation Function(s) | Error Condition |
|---|---|---|
email | isValidEmail | The input does not match a standard email format. |
vcardUrl | isValidURL, isSafeHttpUrl | The input is not a valid URL format, or it uses a protocol other than http:// or https://. |
phone | isValidPhone | The input contains characters other than digits, spaces, +, -, (, ). |
Sources: src/App.jsx:327-332, src/utils/qr-helpers.js:38-60, tests/qr-helpers.test.js:60-91
Validation Flow
The validation process is triggered on every change to the vCard form data.
This sequence diagram shows how valid and invalid inputs are processed, leading to either a clean state or the display of an error message.
Sources: src/App.jsx:319-339, src/utils/qr-helpers.js
The implementation of this logic can be seen in the useEffect hook:
// File: src/App.jsx:326-332
if (qrType === QR_TYPES.VCARD) {
if (qrData.email && !isValidEmail(qrData.email)) e.vcardEmail = 'Email không hợp lệ';
if (qrData.vcardUrl && !isValidURL(qrData.vcardUrl)) e.vcardUrl = 'URL không hợp lệ';
else if (qrData.vcardUrl && !isSafeHttpUrl(qrData.vcardUrl))
e.vcardUrl = '⚠️ Chỉ nên dùng http:// hoặc https://';
if (qrData.phone && !isValidPhone(qrData.phone)) e.vcardPhone = 'Số điện thoại không hợp lệ';
}
Sources: src/App.jsx:326-332
Conclusion
The vCard feature in QR-Tool is a well-structured module that transforms user-provided contact information into a standard vCard 3.0 format suitable for QR code generation. It leverages React's state management for a responsive UI, implements robust data parsing and escaping to ensure format compliance, and integrates real-time input validation to guide the user and prevent malformed data. The clear separation of concerns between UI rendering, state management, and data generation logic makes the feature maintainable and testable, as evidenced by the corresponding unit tests.
Sources: src/App.jsx, src/App.test.js, README.md