Skip to content

4495: Seperating qr design #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 52 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
c6be260
required webpack resources for qr crud
jeppekroghitk May 22, 2025
c2871da
Added qrVisualConfig entity
jeppekroghitk May 23, 2025
a9043cf
Added crud controller for visual config
jeppekroghitk May 23, 2025
d25dde6
Added VisualConfig crud to side menu
jeppekroghitk May 23, 2025
c5351b3
Added a preview for created designs
jeppekroghitk May 23, 2025
76e0c00
Added twig extension to inject functions to generate required classes…
jeppekroghitk May 23, 2025
721227c
Adjusted some styling for qr design preview
jeppekroghitk May 23, 2025
fd52c6c
Added twig extension to defined services
jeppekroghitk May 23, 2025
bfd714d
Added additional methods for getting required endroid class instances
jeppekroghitk May 23, 2025
47a851e
Added repository
jeppekroghitk May 23, 2025
7acc61a
Added migrations
jeppekroghitk May 23, 2025
586cc7a
Editied migration
jeppekroghitk May 23, 2025
eba9a49
Removed migration
jeppekroghitk May 23, 2025
aa0f9c2
Added correct migration
jeppekroghitk May 23, 2025
1e4f7b0
Added standard values to entity
jeppekroghitk May 26, 2025
f0d01b8
Added findOneBy method to qrvisualconfig repo
jeppekroghitk May 26, 2025
ae595ee
Added method for getting visual config entity data
jeppekroghitk May 26, 2025
d10b4dc
Added design selector to download form
jeppekroghitk May 26, 2025
c296e93
Added new config value labelFont to download helper
jeppekroghitk May 26, 2025
8d4ce5a
Added method for getting values from qrVisualConfig and applying valu…
jeppekroghitk May 26, 2025
2e35c0d
Adjusted some styling for qr design preview
jeppekroghitk May 26, 2025
c091865
Minor adjustments to get logo upload to work properly
jeppekroghitk May 26, 2025
0967222
Added logoPath for previewing preselected designs with logos
jeppekroghitk May 26, 2025
3a5c69d
Added custom template when adding new qrVisualConfig (added live prev…
jeppekroghitk May 27, 2025
1f474e3
Added custom template when editing qrVisualConfig (added live preview)
jeppekroghitk May 27, 2025
7eaefd0
Only pass logo data from twig if logo isset in entity
jeppekroghitk May 27, 2025
861ed88
Added some fallback data for logo and logoPath
jeppekroghitk May 27, 2025
424510f
Added logoPath for containing logoPath gotten from QrVisualConfig ent…
jeppekroghitk May 27, 2025
392dc29
Added eventsubscriber for handling uploads
jeppekroghitk May 27, 2025
ffe79ed
Changed logo from being a blob to being a string i.e. path
jeppekroghitk May 27, 2025
a589f97
Added overrides for new and edit pages, as well as some adjustments t…
jeppekroghitk May 27, 2025
d17f239
Modified preview controller to handle both batch download page and vi…
jeppekroghitk May 27, 2025
e6a2597
Added event subscriber to services
jeppekroghitk May 27, 2025
d21b5b7
Adjusted some styling for qr design preview
jeppekroghitk May 27, 2025
c9e8243
Adjusted some of the preview script
jeppekroghitk May 27, 2025
fa32824
Added migration
jeppekroghitk May 27, 2025
49315ab
Added advancedSettingsType for hiding download settings in accordian
jeppekroghitk May 28, 2025
b44934d
Customized batchDownload twig to allow for new advanced settings acco…
jeppekroghitk May 28, 2025
f5459e9
Attached data controller to type
jeppekroghitk May 28, 2025
aec5ab0
Improved easyadmin setup
jeppekroghitk May 28, 2025
585b668
Improved visuals on other crudcontrollers
jeppekroghitk May 28, 2025
b6a5d5e
Styling for accordian
jeppekroghitk May 28, 2025
34a2597
Coding standards
jeppekroghitk May 28, 2025
d1a80a0
Coding standards
jeppekroghitk Jun 2, 2025
ac5bf56
..
jeppekroghitk Jun 2, 2025
bdeeeec
Updated changelog
jeppekroghitk Jun 2, 2025
43fe73c
coding standards
jeppekroghitk Jun 2, 2025
dd38bec
Adjusted field types and removed unused subscriber
jeppekroghitk Jun 2, 2025
aa90ce4
Updated api platform core
jeppekroghitk Jun 2, 2025
423aef5
Updated symfony-ux-twig-component
jeppekroghitk Jun 2, 2025
684c01c
Removed console log
jeppekroghitk Jun 2, 2025
014c209
Merged migrations
jeppekroghitk Jun 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ See [keep a changelog] for information about writing changes to this log.

## [Unreleased]

[PR-23](https://github.com/itk-dev/itqr/pull/23)
- Seperate visual representation of QR into own config
- Live preview of design and download
[PR-22](https://github.com/itk-dev/itqr/pull/22)
- Add temporary form login
- Fix for "tenant null" error on URLs in embedded forms
Expand Down
203 changes: 145 additions & 58 deletions assets/app.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import './styles/app.css';

const uploadBasePath = 'uploads/qr_codes/';
document.addEventListener('DOMContentLoaded', () => {
const qrCodeContainer = document.getElementById('qrCodeContainer');
const tabsContainer = document.getElementById('qrCodeTabs'); // Navigation tabs
const tabContentContainer = document.getElementById('qrCodeTabContent'); // Tab content
const form = document.querySelector('.form-wrapper form');
const formName = form.getAttribute('name');
const selectedQrCodes = document.getElementById('selectedQrCodes');

// Ensure all containers and elements exist
Expand All @@ -20,76 +22,162 @@ document.addEventListener('DOMContentLoaded', () => {
return;
}

let isDesignUpdating = false;
let updatePromise = null;
const designSelect = document.querySelector('#batch_download_design');
if (designSelect) {
designSelect.addEventListener('change', function () {
const selectedOption = this.options[this.selectedIndex];

if (!selectedOption.value) {
// Set default values if no design selected
const defaultFields = {
'size': 400,
'margin': 0,
'backgroundColor': '#ffffff',
'foregroundColor': '#000000',
'labelText': '',
'labelSize': 12,
'labelTextColor': '#000000',
'labelMarginTop': 0,
'labelMarginBottom': 0,
'errorCorrectionLevel': 'medium',
'logo': '',
'logoPath': '',
};

Object.entries(defaultFields).forEach(([field, value]) => {
const input = document.querySelector(`#batch_download_${field}`);
if (input) {
input.value = value;
}
});

return;
}

isDesignUpdating = true;
// Get the design data using the API Platform endpoint
fetch(`/admin/qr_visual_configs/${selectedOption.value}`)
.then(response => response.json())
.then(design => {

console.log(design.logo);
// Update form fields with design values
const fields = {
'size': design.size,
'margin': design.margin,
'backgroundColor': design.backgroundColor,
'foregroundColor': design.foregroundColor,
'labelText': design.labelText || '',
'labelSize': design.labelSize,
'labelTextColor': design.labelTextColor,
'labelMarginTop': design.labelMarginTop,
'labelMarginBottom': design.labelMarginBottom,
'errorCorrectionLevel': design.errorCorrectionLevel,
'logoPath': design.logo,
};

// Update each form field
Object.entries(fields).forEach(([field, value]) => {
const input = document.querySelector(`#batch_download_${field}`);
if (input) {
input.value = value;
}
});

isDesignUpdating = false;
})
.catch(error => {
console.error('Error fetching design details:', error);
isDesignUpdating = false;
});
});
}

async function updateQRCode() {
if (updatePromise) {
return updatePromise;
}

// Clear tab and content containers
tabsContainer.innerHTML = '';
tabContentContainer.innerHTML = '';

// Prepare form data for POST request
const formData = new FormData(form);
formData.append('selectedQrCodes', selectedQrCodes.value);

try {
// Fetch the QR codes from the endpoint
const response = await fetch(generateQrPath, {
method: 'POST',
body: formData,
});

if (response.ok) {
const data = await response.json();
const qrCodes = data.qrCodes; // Array of qr titles and generated base64 images

if (typeof qrCodes === 'object') {
// Loop through all images and create tabs dynamically
Object.entries(qrCodes).forEach(([title, imageSrc]) => {
// Sanitize the title to create valid IDs
const sanitizedTitle = title.replace(/[^a-zA-Z0-9-_]/g, '_');

// Create a unique tab ID
const tabId = `qrCodeTab-${sanitizedTitle}`;
const tabPaneId = `qrCodeContent-${sanitizedTitle}`;

// Create tab navigation item
const tabItem = document.createElement('li');
tabItem.className = 'nav-item';
tabItem.role = 'presentation';
tabItem.innerHTML = `
<button class="nav-link ${tabsContainer.children.length === 0 ? 'active' : ''}"
id="${tabId}"
data-bs-toggle="tab"
data-bs-target="#${tabPaneId}"
type="button"
role="tab"
aria-controls="${tabPaneId}"
aria-selected="${tabsContainer.children.length === 0}">
${title}
</button>
`;
tabsContainer.appendChild(tabItem);

// Create tab content (image)
const tabContent = document.createElement('div');
tabContent.className = `tab-pane fade ${tabsContainer.children.length === 1 ? 'show active' : ''} qr-code-tab-pane`;
tabContent.id = tabPaneId;
tabContent.role = 'tabpanel';
tabContent.innerHTML = `
<img src="${imageSrc}" alt="QR Code titled ${title}" class="qr-code-image">
`;
tabContentContainer.appendChild(tabContent);
});
formData.append('formName', formName);

updatePromise = (async () => {
try {
formData.forEach((value, key) => {
console.log(key + ': ' + value);
});
// Fetch the QR codes from the endpoint
const response = await fetch(generateQrPath, {
method: 'POST',
body: formData,
});

if (response.ok) {
const data = await response.json();
const qrCodes = data.qrCodes; // Array of qr titles and generated base64 images

if (typeof qrCodes === 'object') {
// Loop through all images and create tabs dynamically
Object.entries(qrCodes).forEach(([title, imageSrc]) => {
// Sanitize the title to create valid IDs
const sanitizedTitle = title.replace(/[^a-zA-Z0-9-_]/g, '_');

// Create a unique tab ID
const tabId = `qrCodeTab-${sanitizedTitle}`;
const tabPaneId = `qrCodeContent-${sanitizedTitle}`;

// Create tab navigation item
const tabItem = document.createElement('li');
tabItem.className = 'nav-item';
tabItem.role = 'presentation';
tabItem.innerHTML = `
<button class="nav-link ${tabsContainer.children.length === 0 ? 'active' : ''}"
id="${tabId}"
data-bs-toggle="tab"
data-bs-target="#${tabPaneId}"
type="button"
role="tab"
aria-controls="${tabPaneId}"
aria-selected="${tabsContainer.children.length === 0}">
${title === 'examplePreview' ? '' : title}
</button>
`;
tabsContainer.appendChild(tabItem);

// Create tab content (image)
const tabContent = document.createElement('div');
tabContent.className = `tab-pane fade ${tabsContainer.children.length === 1 ? 'show active' : ''} qr-code-tab-pane`;
tabContent.id = tabPaneId;
tabContent.role = 'tabpanel';
tabContent.innerHTML = `
<img src="${imageSrc}" alt="QR Code titled ${title}" class="qr-code-image">
`;
tabContentContainer.appendChild(tabContent);
});
} else {
console.error('Invalid data format. Expected an array of QR code images.');
}
} else {
console.error('Invalid data format. Expected an array of QR code images.');
console.error('Failed to fetch QR codes. Status:', response.status);
}
} else {
console.error('Failed to fetch QR codes. Status:', response.status);
} catch (error) {
console.error('Error while fetching QR codes:', error);
} finally {
updatePromise = null;
}
} catch (error) {
console.error('Error while fetching QR codes:', error);
}
})();

return updatePromise;
}

// Timeout before updating qr code after typing
let typingTimer;

form.addEventListener('input', () => {
Expand All @@ -99,6 +187,5 @@ document.addEventListener('DOMContentLoaded', () => {
updateQRCode();
}, 500);
});

updateQRCode();
});
37 changes: 34 additions & 3 deletions assets/styles/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@
transform: translateX(-50%);
background-color: white;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
padding: 5px;
z-index: 1000;
white-space: nowrap;
pointer-events: none;
}

.popover-content img {
Expand All @@ -51,10 +50,18 @@
background-color: #f9f9f9;
flex: 1;
height: 475px;
position: sticky;
top: 70px;
z-index: 100;

#qrCodeContainer {
height: 100%;
}
.nav-link {
color: #000;
}


.nav-link.active {
color: #000;
font-weight: bold;
Expand All @@ -66,7 +73,31 @@
}

.qr-preview .qr-code-image {
max-width: 100%;
max-height: 400px;
display: block;
margin: 15px auto 0 auto;
}


.qr-edit-visual-config-container,
.qr-new-visual-config-container {
display: flex;
flex-direction: row;
> div {
flex: 1;
}

.form-fieldset-body {
> div {
> div {
width: 100%;
}
}
}
}

form[name="batch_download"] .accordion-button {
box-shadow: none;
background-color: #fff;
border-bottom: 1px solid #e9e9e9;
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"ext-gd": "*",
"ext-iconv": "*",
"ext-zip": "*",
"api-platform/core": "^4.0.16",
"api-platform/core": "^4.0.22",
"doctrine/dbal": "^3.9.4",
"doctrine/doctrine-bundle": "^2.13.2",
"doctrine/doctrine-migrations-bundle": "^3.4.1",
Expand All @@ -24,6 +24,7 @@
"symfony/maker-bundle": "^1.62.1",
"symfony/runtime": "~7.2.0",
"symfony/twig-bundle": "~7.2.0",
"symfony/ux-twig-component": "^2.25.1",
"symfony/webpack-encore-bundle": "^2.2",
"symfony/yaml": "~7.2.0",
"twig/twig": "^3.19.0"
Expand Down
Loading