s12
parent
ee2bbc817f
commit
5efa3d3270
|
@ -25,6 +25,7 @@
|
||||||
"lucide-react": "^0.484.0",
|
"lucide-react": "^0.484.0",
|
||||||
"pocketbase": "^0.25.2",
|
"pocketbase": "^0.25.2",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
|
"react-qr-code": "^2.0.15",
|
||||||
"react-router-dom": "^7.4.1",
|
"react-router-dom": "^7.4.1",
|
||||||
"react-to-print": "^3.0.5",
|
"react-to-print": "^3.0.5",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.0.2",
|
||||||
|
@ -4524,6 +4525,18 @@
|
||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"loose-envify": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "10.4.3",
|
"version": "10.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
|
@ -6009,6 +6022,17 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prop-types": {
|
||||||
|
"version": "15.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"react-is": "^16.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/property-information": {
|
"node_modules/property-information": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz",
|
||||||
|
@ -6019,6 +6043,12 @@
|
||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/qr.js": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz",
|
||||||
|
"integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
@ -6068,6 +6098,25 @@
|
||||||
"react": "^19.0.0"
|
"react": "^19.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/react-qr-code": {
|
||||||
|
"version": "2.0.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.15.tgz",
|
||||||
|
"integrity": "sha512-MkZcjEXqVKqXEIMVE0mbcGgDpkfSdd8zhuzXEl9QzYeNcw8Hq2oVIzDLWuZN2PQBwM5PWjc2S31K8Q1UbcFMfw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.8.1",
|
||||||
|
"qr.js": "0.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-refresh": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.14.2",
|
"version": "0.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
"lucide-react": "^0.484.0",
|
"lucide-react": "^0.484.0",
|
||||||
"pocketbase": "^0.25.2",
|
"pocketbase": "^0.25.2",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
|
"react-qr-code": "^2.0.15",
|
||||||
"react-router-dom": "^7.4.1",
|
"react-router-dom": "^7.4.1",
|
||||||
"react-to-print": "^3.0.5",
|
"react-to-print": "^3.0.5",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.0.2",
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Toast } from './Toast';
|
import { Toast } from './Toast';
|
||||||
import { TemplatePreview } from './TemplatePreview';
|
import { TemplatePreview } from './TemplatePreview';
|
||||||
|
import { Button } from './ui/button';
|
||||||
|
import { Input } from "./ui/input";
|
||||||
|
import { Label, Select } from '@radix-ui/react-select';
|
||||||
export const DomainSetupForm = ({ defaultSubdomain }) => {
|
export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
// Deployment type and app selections
|
// Deployment type and app selections
|
||||||
const [deploymentType, setDeploymentType] = useState('app');
|
const [deploymentType, setDeploymentType] = useState('app');
|
||||||
|
@ -27,12 +29,73 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
// DNS configuration
|
// DNS configuration
|
||||||
const [dnsMethod, setDnsMethod] = useState('cname');
|
const [dnsMethod, setDnsMethod] = useState('cname');
|
||||||
const [showDnsConfig, setShowDnsConfig] = useState(false);
|
const [showDnsConfig, setShowDnsConfig] = useState(false);
|
||||||
const [dnsVerified, setDnsVerified] = useState({
|
const [dnsVerified, setDnsVerified] = useState({ cname: false, ns: false, a: false, ip: false});
|
||||||
cname: false,
|
const [txnId, setTxnId] = useState('');
|
||||||
ns: false,
|
const [userEmail, setUserEmail] = useState('');
|
||||||
a: false,
|
|
||||||
ip: false
|
const [panelType, setPanelType] = useState('');
|
||||||
|
const API_URL = 'http://192.168.1.197:2058/v1/users/index.php';
|
||||||
|
const SERVICES_API_URL = 'http://192.168.1.197:2058/v1/services/index.php';
|
||||||
|
// const BILLING_API_URL = 'http://192.168.1.197:2058/v1/users/index.php';
|
||||||
|
|
||||||
|
const [selectedTenure, setSelectedTenure] = useState('');
|
||||||
|
const [selectedPrice, setSelectedPrice] = useState(0);
|
||||||
|
|
||||||
|
const handleCheckboxChange = (tenure, price) => {
|
||||||
|
if (selectedTenure === tenure) {
|
||||||
|
setSelectedTenure('');
|
||||||
|
setSelectedPrice(0);
|
||||||
|
} else {
|
||||||
|
setSelectedTenure(tenure);
|
||||||
|
setSelectedPrice(price);
|
||||||
|
}
|
||||||
|
// console.log(selectedTenure, ' ', selectedPrice);
|
||||||
|
};
|
||||||
|
const handlePanelBuyNow = () => {
|
||||||
|
// Disable button during processing
|
||||||
|
const buyButton = document.getElementById('buy-button'); // Add ID to your button
|
||||||
|
if (buyButton) buyButton.disabled = true;
|
||||||
|
|
||||||
|
showToast('Loading...');
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('service', panelType);
|
||||||
|
formData.append('tenure', selectedTenure);
|
||||||
|
formData.append('amount', 1); //selectedPrice
|
||||||
|
|
||||||
|
fetch(`${API_URL}?query=initiate_payment`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
credentials: 'include'
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if(data.success === true){
|
||||||
|
setTxnId(data.txn_id);
|
||||||
|
setUserEmail(data.user_email);
|
||||||
|
window.location.href = `/make-payment?query=get-initiated_payment&orderId=${data.order_id}`
|
||||||
|
// redirectToPayU(data);
|
||||||
|
showToast('Redirecting to payment page...');
|
||||||
|
} else {
|
||||||
|
throw new Error(data.message || 'Payment initialization failed');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
showToast(error.message || 'Payment failed. Please try again.');
|
||||||
|
console.error('An error occurred:', error);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (buyButton) buyButton.disabled = false;
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Form validation
|
// Form validation
|
||||||
const [formValid, setFormValid] = useState(true);
|
const [formValid, setFormValid] = useState(true);
|
||||||
|
@ -159,52 +222,71 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate domain
|
// Validate domain
|
||||||
const validateDomain = () => {
|
const validateDomain = async () => {
|
||||||
const domain = domainType === 'domain' ? customDomain : customSubdomain;
|
const domain = domainType === 'domain' ? customDomain : customSubdomain;
|
||||||
|
|
||||||
if (!domain) {
|
// Reset validation state
|
||||||
setValidationMessage('Please enter a domain name.');
|
|
||||||
setIsValidDomain(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initial validation: check format with regex
|
|
||||||
const validFormat = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/.test(domain);
|
|
||||||
if (!validFormat) {
|
|
||||||
setValidationMessage('Domain format is invalid. Please check your entry.');
|
|
||||||
setIsValidDomain(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsValidating(true);
|
setIsValidating(true);
|
||||||
|
setIsValidDomain(false);
|
||||||
setValidationMessage('');
|
setValidationMessage('');
|
||||||
setShowDnsConfig(false);
|
setShowDnsConfig(false);
|
||||||
|
|
||||||
// Simulate an API call to validate the domain
|
// Check if domain is empty
|
||||||
setTimeout(() => {
|
if (!domain) {
|
||||||
// Simulate a real domain check - in a real app this would be an API call
|
setValidationMessage('Please enter a domain name.');
|
||||||
// call /host-api/v1/domains/validate/?domain=domain.com
|
|
||||||
const checkResult = true; // Assume domain is valid for demo
|
|
||||||
|
|
||||||
setIsValidating(false);
|
setIsValidating(false);
|
||||||
setIsValidDomain(checkResult);
|
setIsValidDomain(false);
|
||||||
|
return;
|
||||||
if (checkResult) {
|
|
||||||
setValidationMessage('Domain is valid and registered.');
|
|
||||||
setShowDnsConfig(true);
|
|
||||||
} else {
|
|
||||||
setValidationMessage('Domain appears to be unregistered or unavailable.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate domain format
|
||||||
|
const domainFormatRegex = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i;
|
||||||
|
if (!domainFormatRegex.test(domain)) {
|
||||||
|
setValidationMessage('Domain format is invalid. Please check your entry.');
|
||||||
|
setIsValidating(false);
|
||||||
|
setIsValidDomain(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Make API call to validate domain
|
||||||
|
const response = await fetch(`${SERVICES_API_URL}?query=validate-domain`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ domain })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.valid) {
|
||||||
|
setValidationMessage('Domain is valid and registered.');
|
||||||
|
setIsValidDomain(true);
|
||||||
|
setShowDnsConfig(true);
|
||||||
|
} else {
|
||||||
|
setValidationMessage(data.message || 'Domain appears to be unregistered or unavailable.');
|
||||||
|
setIsValidDomain(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Domain validation error:', error);
|
||||||
|
setValidationMessage('Error validating domain. Please try again.');
|
||||||
|
setIsValidDomain(false);
|
||||||
|
} finally {
|
||||||
|
setIsValidating(false);
|
||||||
validateForm();
|
validateForm();
|
||||||
}, 500);
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check DNS configuration
|
// Check DNS configuration
|
||||||
const checkSubDomainCname = () => {
|
const checkSubDomainCname = () => {
|
||||||
const domainToCheck = customDomain || customSubdomain;
|
const domainToCheck = customDomain || customSubdomain;
|
||||||
|
|
||||||
fetch('http://localhost:2058/host-api/v1/check-c-name/', {
|
fetch(`${SERVICES_API_URL}?query=check-c-name`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
@ -312,6 +394,7 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
<option value="source">⚙️ From Source</option>
|
<option value="source">⚙️ From Source</option>
|
||||||
<option value="static">📄 Static Site Upload</option>
|
<option value="static">📄 Static Site Upload</option>
|
||||||
<option value="sample-web-app">🌐 Sample Web App</option>
|
<option value="sample-web-app">🌐 Sample Web App</option>
|
||||||
|
<option value="php-mysql-with-admin-panel">🗄️ PHP MYSQL with a admin panel</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -461,7 +544,74 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{
|
||||||
|
deploymentType === 'php-mysql-with-admin-panel' && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label htmlFor="app-type" className="block text-white font-medium">Select Panel</label>
|
||||||
|
<select
|
||||||
|
id="app-type"
|
||||||
|
value={panelType}
|
||||||
|
onChange={(e) => setPanelType(e.target.value)}
|
||||||
|
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||||||
|
>
|
||||||
|
<option value="">-Select-</option>
|
||||||
|
<option value="Hestia-Panel">🧰 Hestia Panel</option>
|
||||||
|
<option value="Webmin">🖥️ Webmin</option>
|
||||||
|
<option value="cPanel">📊 cPanel</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
{
|
||||||
|
deploymentType === 'php-mysql-with-admin-panel' && panelType === 'Hestia-Panel' && (
|
||||||
|
<>
|
||||||
|
<ul className="flex justify-between text-sm">
|
||||||
|
{["5 Domains", "free Let's Encrypt SSL", "1 MariaDB database", "phpMyAdmin"].map((feature, index) => (
|
||||||
|
<li key={index} className="flex items-start">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-2 text-[#6d9e37] shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" ><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /></svg>
|
||||||
|
<span className='text-zinc-400'>{feature}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<div className='flex flex-row justify-between items-center gap-x-6'>
|
||||||
|
<label className={`border ${selectedTenure === 'monthly' ? 'bg-[#6d9e37]' : ''} border-[#6d9e37] text-white px-4 py-2 text-center rounded-md w-full cursor-pointer`}>
|
||||||
|
<input type="checkbox" checked={selectedTenure === 'monthly'} onChange={() => handleCheckboxChange('monthly', 200)} className="hidden" />
|
||||||
|
<p className='text-3xl font-bold text-center'>₹200</p>
|
||||||
|
<span>Monthly</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label className={`border ${selectedTenure === 'yearly' ? 'bg-[#6d9e37]' : ''} border-[#6d9e37] text-white px-4 py-2 text-center rounded-md w-full cursor-pointer`}>
|
||||||
|
<input type="checkbox" checked={selectedTenure === 'yearly'} onChange={() => handleCheckboxChange('yearly', 2000)} className="hidden" />
|
||||||
|
<p className='text-3xl font-bold text-center'>₹2000</p>
|
||||||
|
<span>Yearly</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className='text-white'>
|
||||||
|
{selectedTenure && (
|
||||||
|
<p className={`${selectedTenure === 'monthly' ? 'text-left' : 'text-end'}`}>You selected <strong>{selectedTenure}</strong> plan at ₹{selectedPrice}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
deploymentType === 'php-mysql-with-admin-panel' && panelType === 'cPanel' ? (
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
cPanel is a proprietary software. Here at Siliconpin, we encourage using freedom-oriented software.
|
||||||
|
If you need a cPanel, you can visit
|
||||||
|
<a className='text-[#6d9e37]' href="https://cicdhosting.com" target='_blank'>https://cicdhosting.com</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
) : deploymentType === 'php-mysql-with-admin-panel' && (
|
||||||
|
<Button onClick={handlePanelBuyNow} className='w-full'>Proceed to Pay</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
deploymentType !== 'php-mysql-with-admin-panel' && (
|
||||||
|
<>
|
||||||
{/* Domain Configuration */}
|
{/* Domain Configuration */}
|
||||||
<div className="pt-4 border-t border-neutral-700">
|
<div className="pt-4 border-t border-neutral-700">
|
||||||
<h3 className="text-lg font-medium text-white mb-4">Destination</h3>
|
<h3 className="text-lg font-medium text-white mb-4">Destination</h3>
|
||||||
|
@ -469,13 +619,7 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* SiliconPin Subdomain */}
|
{/* SiliconPin Subdomain */}
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<input
|
<input type="checkbox" id="use-subdomain" checked={useSubdomain} onChange={handleUseSubdomainChange} className="mt-1 accent-[#6d9e37]" />
|
||||||
type="checkbox"
|
|
||||||
id="use-subdomain"
|
|
||||||
checked={useSubdomain}
|
|
||||||
onChange={handleUseSubdomainChange}
|
|
||||||
className="mt-1"
|
|
||||||
/>
|
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<label htmlFor="use-subdomain" className="block text-white font-medium">Use SiliconPin Subdomain</label>
|
<label htmlFor="use-subdomain" className="block text-white font-medium">Use SiliconPin Subdomain</label>
|
||||||
<div className="mt-2 flex">
|
<div className="mt-2 flex">
|
||||||
|
@ -493,13 +637,7 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
|
|
||||||
{/* Custom Domain */}
|
{/* Custom Domain */}
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<input
|
<input type="checkbox" id="use-custom-domain" checked={useCustomDomain} onChange={handleUseCustomDomainChange} className="mt-1 accent-[#6d9e37]" />
|
||||||
type="checkbox"
|
|
||||||
id="use-custom-domain"
|
|
||||||
checked={useCustomDomain}
|
|
||||||
onChange={handleUseCustomDomainChange}
|
|
||||||
className="mt-1"
|
|
||||||
/>
|
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<label htmlFor="use-custom-domain" className="block text-white font-medium">Use Custom Domain</label>
|
<label htmlFor="use-custom-domain" className="block text-white font-medium">Use Custom Domain</label>
|
||||||
|
|
||||||
|
@ -508,28 +646,12 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
{/* Domain Type Selection */}
|
{/* Domain Type Selection */}
|
||||||
<div className="flex flex-col space-y-3 sm:flex-row sm:space-y-0 sm:space-x-4">
|
<div className="flex flex-col space-y-3 sm:flex-row sm:space-y-0 sm:space-x-4">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<input
|
<input type="radio" id="domain-type-domain" name="domain-type" value="domain" checked={domainType === 'domain'} onChange={handleDomainTypeChange} className="mr-2 accent-[#6d9e37]" />
|
||||||
type="radio"
|
|
||||||
id="domain-type-domain"
|
|
||||||
name="domain-type"
|
|
||||||
value="domain"
|
|
||||||
checked={domainType === 'domain'}
|
|
||||||
onChange={handleDomainTypeChange}
|
|
||||||
className="mr-2"
|
|
||||||
/>
|
|
||||||
<label htmlFor="domain-type-domain" className="text-white">Root Domain</label>
|
<label htmlFor="domain-type-domain" className="text-white">Root Domain</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<input
|
<input type="radio" id="domain-type-subdomain" name="domain-type" value="subdomain" checked={domainType === 'subdomain'} onChange={handleDomainTypeChange} className="mr-2 accent-[#6d9e37]"/>
|
||||||
type="radio"
|
|
||||||
id="domain-type-subdomain"
|
|
||||||
name="domain-type"
|
|
||||||
value="subdomain"
|
|
||||||
checked={domainType === 'subdomain'}
|
|
||||||
onChange={handleDomainTypeChange}
|
|
||||||
className="mr-2"
|
|
||||||
/>
|
|
||||||
<label htmlFor="domain-type-subdomain" className="text-white">Subdomain</label>
|
<label htmlFor="domain-type-subdomain" className="text-white">Subdomain</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -599,17 +721,9 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
<h4 className="text-white font-medium">Connect Your Domain</h4>
|
<h4 className="text-white font-medium">Connect Your Domain</h4>
|
||||||
|
|
||||||
{/* CNAME Record Option */}
|
{/* CNAME Record Option */}
|
||||||
<div className="p-4 bg-neutral-700/30 rounded-md border border-neutral-600 space-y-3">
|
<div className={`p-4 bg-neutral-700/30 rounded-md space-y-3 ${dnsMethod === 'cname' ? 'border-2 border-[#6d9e37]' : 'border border-neutral-600'}`}>
|
||||||
<label for="dns-cname" className="flex items-start cursor-pointer">
|
<label for="dns-cname" className={`flex items-start cursor-pointer`}>
|
||||||
<input
|
<input type="radio" id="dns-cname" name="dns-method" value="cname" checked={dnsMethod === 'cname'} onChange={handleDnsMethodChange} className="mt-1 mr-2 accent-[#6d9e37]" />
|
||||||
type="radio"
|
|
||||||
id="dns-cname"
|
|
||||||
name="dns-method"
|
|
||||||
value="cname"
|
|
||||||
checked={dnsMethod === 'cname'}
|
|
||||||
onChange={handleDnsMethodChange}
|
|
||||||
className="mt-1 mr-2"
|
|
||||||
/>
|
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<label htmlFor="dns-cname" className="block text-white font-medium">Use CNAME Record</label>
|
<label htmlFor="dns-cname" className="block text-white font-medium">Use CNAME Record</label>
|
||||||
<p className="text-sm text-neutral-300">Point your domain to our SiliconPin subdomain</p>
|
<p className="text-sm text-neutral-300">Point your domain to our SiliconPin subdomain</p>
|
||||||
|
@ -646,17 +760,9 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
{/* Nameserver Option (only for full domains, not subdomains) */}
|
{/* Nameserver Option (only for full domains, not subdomains) */}
|
||||||
{domainType === 'domain' && (
|
{domainType === 'domain' && (
|
||||||
<>
|
<>
|
||||||
<div className="p-4 bg-neutral-700/30 rounded-md border border-neutral-600 space-y-3">
|
<div className={`p-4 bg-neutral-700/30 rounded-md space-y-3 ${dnsMethod === 'ns' ? 'border-2 border-[#6d9e37]' : 'border border-neutral-600'}`}>
|
||||||
<label for="dns-ns" className="flex items-start cursor-pointer">
|
<label for="dns-ns" className="flex items-start cursor-pointer">
|
||||||
<input
|
<input type="radio" id="dns-ns" name="dns-method" value="ns" checked={dnsMethod === 'ns'} onChange={handleDnsMethodChange} className="mt-1 mr-2 accent-[#6d9e37]" />
|
||||||
type="radio"
|
|
||||||
id="dns-ns"
|
|
||||||
name="dns-method"
|
|
||||||
value="ns"
|
|
||||||
checked={dnsMethod === 'ns'}
|
|
||||||
onChange={handleDnsMethodChange}
|
|
||||||
className="mt-1 mr-2"
|
|
||||||
/>
|
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<label htmlFor="dns-ns" className="block text-white font-medium">Use Our Nameservers</label>
|
<label htmlFor="dns-ns" className="block text-white font-medium">Use Our Nameservers</label>
|
||||||
<p className="text-sm text-neutral-300">Update your domain's nameservers to use ours</p>
|
<p className="text-sm text-neutral-300">Update your domain's nameservers to use ours</p>
|
||||||
|
@ -664,24 +770,14 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
<div className="mt-3 space-y-2">
|
<div className="mt-3 space-y-2">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">ns1.siliconpin.com</div>
|
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">ns1.siliconpin.com</div>
|
||||||
<button
|
<button type="button" onClick={() => copyToClipboard('ns1.siliconpin.com')} className="ml-2 text-[#6d9e37] hover:text-white" aria-label="Copy nameserver value">
|
||||||
type="button"
|
|
||||||
onClick={() => copyToClipboard('ns1.siliconpin.com')}
|
|
||||||
className="ml-2 text-[#6d9e37] hover:text-white"
|
|
||||||
aria-label="Copy nameserver value"
|
|
||||||
>
|
|
||||||
<span className="text-lg">📋</span>
|
<span className="text-lg">📋</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">ns2.siliconpin.com</div>
|
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">ns2.siliconpin.com</div>
|
||||||
<button
|
<button type="button" onClick={() => copyToClipboard('ns2.siliconpin.com')} className="ml-2 text-[#6d9e37] hover:text-white" aria-label="Copy nameserver value">
|
||||||
type="button"
|
|
||||||
onClick={() => copyToClipboard('ns2.siliconpin.com')}
|
|
||||||
className="ml-2 text-[#6d9e37] hover:text-white"
|
|
||||||
aria-label="Copy nameserver value"
|
|
||||||
>
|
|
||||||
<span className="text-lg">📋</span>
|
<span className="text-lg">📋</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -703,30 +799,16 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-4 bg-neutral-700/30 rounded-md border border-neutral-600 space-y-3">
|
<div className={`p-4 bg-neutral-700/30 rounded-md space-y-3 ${dnsMethod === 'ip' ? 'border-2 border-[#6d9e37]' : 'border border-neutral-600'}`}>
|
||||||
<label for="dns-ip" className="flex items-start cursor-pointer">
|
<label for="dns-ip" className="flex items-start cursor-pointer">
|
||||||
<input
|
<input type="radio" id="dns-ip" name="dns-method" value="ip" checked={dnsMethod === 'ip'} onChange={handleDnsMethodChange} className="mt-1 mr-2 accent-[#6d9e37]" />
|
||||||
type="radio"
|
|
||||||
id="dns-ip"
|
|
||||||
name="dns-method"
|
|
||||||
value="ip"
|
|
||||||
checked={dnsMethod === 'ip'}
|
|
||||||
onChange={handleDnsMethodChange}
|
|
||||||
className="mt-1 mr-2"
|
|
||||||
/>
|
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<label htmlFor="dns-ip" className="block text-white font-medium">Use Our IP Address</label>
|
<label htmlFor="dns-ip" className="block text-white font-medium">Use Our IP Address</label>
|
||||||
<p className="text-sm text-neutral-300">Update your domain's nameservers to use ours</p>
|
<p className="text-sm text-neutral-300">Update your domain's nameservers to use ours</p>
|
||||||
|
|
||||||
<div className="mt-3 space-y-2">
|
<div className="mt-3 space-y-2">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">xxx.xxx.x.xx</div>
|
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">xxx.xxx.x.xx</div>
|
||||||
<button
|
<button type="button" onClick={() => copyToClipboard('xxx.xxx.x.xx')} className="ml-2 text-[#6d9e37] hover:text-white" aria-label="Copy nameserver value">
|
||||||
type="button"
|
|
||||||
onClick={() => copyToClipboard('xxx.xxx.x.xx')}
|
|
||||||
className="ml-2 text-[#6d9e37] hover:text-white"
|
|
||||||
aria-label="Copy nameserver value"
|
|
||||||
>
|
|
||||||
<span className="text-lg">📋</span>
|
<span className="text-lg">📋</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -758,7 +840,7 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Form Submit Button */}
|
{/* Form Submit Button */}
|
||||||
<button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={useCustomDomain && !formValid}
|
disabled={useCustomDomain && !formValid}
|
||||||
className={`w-full mt-6 px-6 py-3 text-white font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-neutral-800
|
className={`w-full mt-6 px-6 py-3 text-white font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-neutral-800
|
||||||
|
@ -768,9 +850,15 @@ export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Start the Deployment
|
Start the Deployment
|
||||||
</button>
|
</Button>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
</form>
|
</form>
|
||||||
<Toast visible={toast.visible} message={toast.message} />
|
<Toast visible={toast.visible} message={toast.message} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
// upi://pay?pa=merchant@bank&pn=Merchant%20Inc&am=100.00&cu=INR&tn=Payment%20for%20goods
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,8 @@ interface AuthResponse {
|
||||||
|
|
||||||
|
|
||||||
const LoginPage = () => {
|
const LoginPage = () => {
|
||||||
const [email, setEmail] = useState('suvodip@siliconpin.com');
|
const [email, setEmail] = useState('');
|
||||||
const [password, setPassword] = useState('Simple2pass');
|
const [password, setPassword] = useState('');
|
||||||
const [passwordVisible, setPasswordVisible] = useState(false);
|
const [passwordVisible, setPasswordVisible] = useState(false);
|
||||||
const [status, setStatus] = useState<AuthStatus>({ message: '', isError: false });
|
const [status, setStatus] = useState<AuthStatus>({ message: '', isError: false });
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
@ -118,7 +118,7 @@ const LoginPage = () => {
|
||||||
|
|
||||||
const syncSessionWithBackend = async (authData: AuthResponse, avatarUrl: string) => {
|
const syncSessionWithBackend = async (authData: AuthResponse, avatarUrl: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('http://localhost:2058/host-api/v1/users/session/', {
|
const response = await fetch('http://192.168.1.197:2058/v1/users/?query=login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include', // Important for cookies
|
credentials: 'include', // Important for cookies
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
import React, {useState, useEffect} from "react";
|
||||||
|
import { Button } from "./ui/button";
|
||||||
|
import QRCode from "react-qr-code";
|
||||||
|
import { Dialog, DialogContent, DialogHeader, DialogTitle} from "./ui/dialog";
|
||||||
|
import { Toast } from './Toast';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "./ui/card";
|
||||||
|
|
||||||
|
const API_URL = 'http://192.168.1.197:2058/v1/users/index.php';
|
||||||
|
|
||||||
|
export default function MakePayment(){
|
||||||
|
const [initialOrderData, setInitialOrderData] = useState(null);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
const [showQRModal, setShowQRModal] = useState(false);
|
||||||
|
const [upiPaymentLink, setUpiPaymentLink] = useState("");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const orderId = urlParams.get('orderId');
|
||||||
|
|
||||||
|
if (!orderId) {
|
||||||
|
setError('Order ID is missing from URL');
|
||||||
|
setIsLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getInitialOrderData = () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('order_id', orderId);
|
||||||
|
|
||||||
|
fetch(`${API_URL}?query=get-initiated_payment`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
credentials: 'include'
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (!data.success) {
|
||||||
|
throw new Error(data.message || 'Failed to initialize payment');
|
||||||
|
}
|
||||||
|
setInitialOrderData(data);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
// Generate UPI payment link when data is loaded
|
||||||
|
if (data.payment_data?.amount) {
|
||||||
|
const amount = data.payment_data.amount;
|
||||||
|
const upiLink = generateUPILink(amount, data.txn_id);
|
||||||
|
setUpiPaymentLink(upiLink);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
setError(error.message || 'Payment failed. Please try again.');
|
||||||
|
console.error('An error occurred:', error);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getInitialOrderData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
function generateUPILink(amount, transactionId) {
|
||||||
|
// Replace these with your actual merchant details
|
||||||
|
const merchantUPI = "siliconpin@ybl";
|
||||||
|
const merchantName = "SiliconPin";
|
||||||
|
const currency = "INR";
|
||||||
|
|
||||||
|
// Encode parameters for URL
|
||||||
|
const encodedMerchantName = encodeURIComponent(merchantName);
|
||||||
|
const transactionNote = encodeURIComponent(`Payment for order #${transactionId}`);
|
||||||
|
|
||||||
|
// Construct UPI payment link
|
||||||
|
return `upi://pay?pa=${merchantUPI}&pn=${encodedMerchantName}&am=${amount}&cu=${currency}&tn=${transactionNote}`;
|
||||||
|
}
|
||||||
|
// waiting payment update
|
||||||
|
// Payment update not recieved if
|
||||||
|
function redirectToPayU() {
|
||||||
|
if (!initialOrderData?.payment_data || !initialOrderData.payment_url) {
|
||||||
|
console.error('Payment data not loaded yet');
|
||||||
|
alert('Payment information is not ready. Please wait.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a form dynamically
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.method = 'POST';
|
||||||
|
form.action = initialOrderData.payment_url;
|
||||||
|
form.style.display = 'none';
|
||||||
|
|
||||||
|
Object.entries(initialOrderData.payment_data).forEach(([key, value]) => {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'hidden';
|
||||||
|
input.name = key;
|
||||||
|
input.value = value;
|
||||||
|
form.appendChild(input);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleQRPaymentClick() {
|
||||||
|
if (!upiPaymentLink) {
|
||||||
|
alert('Payment information is not ready. Please wait.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setShowQRModal(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <div className="flex items-center justify-center min-h-screen">
|
||||||
|
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <div className="flex items-center justify-center min-h-screen">
|
||||||
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
||||||
|
<strong>Error:</strong> {error}
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-screen p-4">
|
||||||
|
<Card className="max-w-md w-full bg-white p-6 rounded-lg shadow-md">
|
||||||
|
<h1 className="text-2xl font-bold mb-4">Complete Your Payment</h1>
|
||||||
|
|
||||||
|
{initialOrderData && (
|
||||||
|
<div className="mb-6 p-4 bg-gray-50 rounded-lg">
|
||||||
|
<div className="flex justify-between mb-2">
|
||||||
|
<span className="font-bold">Order ID:</span>
|
||||||
|
<span>{initialOrderData.txn_id}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="font-bold">Amount:</span>
|
||||||
|
<span>₹{initialOrderData.payment_data?.amount}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className=""><strong>Pay Using:</strong></span>
|
||||||
|
<Button variant="outline" className="" onClick={handleQRPaymentClick} >UPI QR</Button>
|
||||||
|
<span className="text-gray-500 text-center font-semibold my-2">OR</span>
|
||||||
|
<Button className="" onClick={redirectToPayU} >Payment Gateway</Button>
|
||||||
|
<span className="text-center mt-2 text-gray-400 text-xs">Applicabel 2% Transaction Charge if using Payment Gateway</span>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* QR Code Modal */}
|
||||||
|
<Dialog open={showQRModal} onOpenChange={setShowQRModal}>
|
||||||
|
<DialogContent className="sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Scan QR Code to Pay</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="flex flex-col items-center space-y-4">
|
||||||
|
<div className="p-4 bg-white rounded-lg border border-gray-200">
|
||||||
|
<QRCode value={upiPaymentLink} size={256} level="H" bgColor="#ffffff" fgColor="#000000" />
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-gray-500 text-center">
|
||||||
|
Scan this QR code with any UPI app to complete your payment
|
||||||
|
</p>
|
||||||
|
<div className="w-full p-3 bg-gray-100 text-gray-500 rounded-md break-all text-xs">
|
||||||
|
{upiPaymentLink}
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" onClick={() => navigator.clipboard.writeText(upiPaymentLink)} className="text-sm" >Copy UPI Link</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
export default function DeployWordPress() {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [message, setMessage] = useState("");
|
||||||
|
const [debugInfo, setDebugInfo] = useState(null);
|
||||||
|
|
||||||
|
// Configuration - Replace with your actual values
|
||||||
|
const COOLIFY_API_URL = "http://192.168.1.197:8000/api/v1";
|
||||||
|
const TOKEN = "zXSR33z74eK26abbKyL9bz4d3PYouTSK8FSjOltv719c52d8";
|
||||||
|
const PROJECT_UUID = "wc40gg048gkwg0go80ggog44";
|
||||||
|
const SERVER_UUID = "sgswssowscc84o8sc8wockgc";
|
||||||
|
const ENVIRONMENT_NAME = "production"; // Changed from 'dev' to 'production' as default
|
||||||
|
|
||||||
|
const createWordPress = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
setMessage("");
|
||||||
|
setDebugInfo(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Create MySQL Service - Updated to Coolify's expected format
|
||||||
|
const mysqlPayload = {
|
||||||
|
name: "wordpress-db",
|
||||||
|
type: "mysql",
|
||||||
|
projectUuid: PROJECT_UUID,
|
||||||
|
serverUuid: SERVER_UUID,
|
||||||
|
version: "8.0",
|
||||||
|
destination: { // Coolify often requires this structure
|
||||||
|
serverUuid: SERVER_UUID,
|
||||||
|
environment: ENVIRONMENT_NAME
|
||||||
|
},
|
||||||
|
configuration: {
|
||||||
|
type: "mysql",
|
||||||
|
settings: { // Changed from environmentVariables to settings
|
||||||
|
MYSQL_ROOT_PASSWORD: "example",
|
||||||
|
MYSQL_DATABASE: "wordpress",
|
||||||
|
MYSQL_USER: "wordpress",
|
||||||
|
MYSQL_PASSWORD: "example",
|
||||||
|
MYSQL_ALLOW_EMPTY_PASSWORD: "no"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mysqlRes = await fetch(`${COOLIFY_API_URL}/services`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${TOKEN}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(mysqlPayload),
|
||||||
|
});
|
||||||
|
|
||||||
|
const mysqlData = await mysqlRes.json();
|
||||||
|
setDebugInfo({ mysql: { request: mysqlPayload, response: mysqlData } });
|
||||||
|
|
||||||
|
if (!mysqlRes.ok) {
|
||||||
|
throw new Error(
|
||||||
|
mysqlData.message ||
|
||||||
|
mysqlData.error?.message ||
|
||||||
|
JSON.stringify(mysqlData.errors) ||
|
||||||
|
"MySQL validation failed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Create WordPress Service
|
||||||
|
const wpPayload = {
|
||||||
|
name: "wordpress",
|
||||||
|
type: "wordpress",
|
||||||
|
projectUuid: PROJECT_UUID,
|
||||||
|
serverUuid: SERVER_UUID,
|
||||||
|
version: "latest",
|
||||||
|
destination: {
|
||||||
|
serverUuid: SERVER_UUID,
|
||||||
|
environment: ENVIRONMENT_NAME
|
||||||
|
},
|
||||||
|
configuration: {
|
||||||
|
type: "wordpress",
|
||||||
|
settings: {
|
||||||
|
WORDPRESS_DB_HOST: "wordpress-db",
|
||||||
|
WORDPRESS_DB_USER: "wordpress",
|
||||||
|
WORDPRESS_DB_PASSWORD: "example",
|
||||||
|
WORDPRESS_DB_NAME: "wordpress",
|
||||||
|
WORDPRESS_TABLE_PREFIX: "wp_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const wpRes = await fetch(`${COOLIFY_API_URL}/services`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${TOKEN}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(wpPayload),
|
||||||
|
});
|
||||||
|
|
||||||
|
const wpData = await wpRes.json();
|
||||||
|
setDebugInfo(prev => ({ ...prev, wordpress: { request: wpPayload, response: wpData } }));
|
||||||
|
|
||||||
|
if (!wpRes.ok) {
|
||||||
|
throw new Error(
|
||||||
|
wpData.message ||
|
||||||
|
wpData.error?.message ||
|
||||||
|
JSON.stringify(wpData.errors) ||
|
||||||
|
"WordPress validation failed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setMessage("🎉 WordPress + MySQL deployed successfully!");
|
||||||
|
} catch (err) {
|
||||||
|
setMessage(`❌ Deployment failed: ${err.message}`);
|
||||||
|
console.error("Deployment error:", err, debugInfo);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-6 max-w-md mx-auto bg-white rounded-xl shadow-md">
|
||||||
|
<h2 className="text-2xl font-bold mb-4">Deploy WordPress</h2>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={createWordPress}
|
||||||
|
disabled={loading}
|
||||||
|
className={`w-full py-2 px-4 rounded-md text-white font-medium ${
|
||||||
|
loading ? "bg-gray-400 cursor-not-allowed" : "bg-blue-600 hover:bg-blue-700"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{loading ? (
|
||||||
|
<span className="flex items-center justify-center">
|
||||||
|
<svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||||||
|
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
</svg>
|
||||||
|
Deploying...
|
||||||
|
</span>
|
||||||
|
) : "Deploy WordPress"}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{message && (
|
||||||
|
<div className={`mt-4 p-3 rounded-md ${
|
||||||
|
message.includes("❌") ? "bg-red-50 text-red-700" : "bg-green-50 text-green-700"
|
||||||
|
}`}>
|
||||||
|
{message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{debugInfo && (
|
||||||
|
<div className="mt-4 space-y-4">
|
||||||
|
<details className="bg-gray-50 rounded-md p-2">
|
||||||
|
<summary className="font-medium cursor-pointer">Debug Details</summary>
|
||||||
|
<div className="mt-2 bg-white p-2 rounded border border-gray-200 overflow-auto max-h-60">
|
||||||
|
<pre>{JSON.stringify(debugInfo, null, 2)}</pre>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p className="font-medium">Troubleshooting:</p>
|
||||||
|
<ul className="list-disc pl-5 space-y-1 mt-1">
|
||||||
|
<li>Verify <code>PROJECT_UUID</code> and <code>SERVER_UUID</code> are correct</li>
|
||||||
|
<li>Check if environment <code>{ENVIRONMENT_NAME}</code> exists</li>
|
||||||
|
<li>Ensure your Coolify version supports this API format</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// [{"uuid":"sgswssowscc84o8sc8wockgc","description":"This is the server where Coolify is running on. Don't delete this!","name":"localhost","ip":"host.docker.internal","is_coolify_host":true,"is_reachable":true,"is_usable":true,"port":22,"proxy":{"redirect_enabled":true},"settings":{"id":1,"concurrent_builds":2,"delete_unused_networks":false,"delete_unused_volumes":false,"docker_cleanup_frequency":"0 0 * * *","docker_cleanup_threshold":80,"dynamic_timeout":3600,"force_disabled":false,"force_docker_cleanup":true,"generate_exact_labels":false,"is_build_server":false,"is_cloudflare_tunnel":false,"is_jump_server":false,"is_logdrain_axiom_enabled":false,"is_logdrain_custom_enabled":false,"is_logdrain_highlight_enabled":false,"is_logdrain_newrelic_enabled":false,"is_metrics_enabled":false,"is_reachable":true,"is_sentinel_debug_enabled":false,"is_sentinel_enabled":false,"is_swarm_manager":false,"is_swarm_worker":false,"is_usable":true,"logdrain_axiom_api_key":null,"logdrain_axiom_dataset_name":null,"logdrain_custom_config":null,"logdrain_custom_config_parser":null,"logdrain_highlight_project_id":null,"logdrain_newrelic_base_uri":null,"logdrain_newrelic_license_key":null,"sentinel_custom_url":"http:\/\/host.docker.internal:8000","sentinel_metrics_history_days":7,"sentinel_metrics_refresh_rate_seconds":10,"sentinel_push_interval_seconds":60,"sentinel_token":"eyJpdiI6IllwMlBsOUtXODdUR0ZIbWtZenJRWFE9PSIsInZhbHVlIjoiZFUxcE9zSXFXdkVrN0tDUGdSbHpGVTE3cHVEeFlBM1hFWk56S05NVWVmVmxHV0tBQ2kra25uRnVzRzNHaFpBSGVTaGZLMGpqdS9nMU85MXhmS3VYMVE9PSIsIm1hYyI6ImY3ODQyNGI2OTVlMmRiMzFmNzJjZjRlYjNkNDIxOGVmZTAxOWMyNjY0ZTYxODE5MDIwY2FhMGUwYjU4ODMyN2MiLCJ0YWciOiIifQ==","server_disk_usage_check_frequency":"0 23 * * *","server_disk_usage_notification_threshold":80,"server_id":0,"server_timezone":"UTC","wildcard_domain":null,"created_at":"2025-04-03T17:12:45.000000Z","updated_at":"2025-04-03T17:16:25.000000Z"},"user":"root"}]
|
|
@ -1,6 +1,5 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./ui/card";
|
|
||||||
import Table from "./ui/table";
|
import Table from "./ui/table";
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "./ui/dialog";
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "./ui/dialog";
|
||||||
import { Input } from "./ui/input";
|
import { Input } from "./ui/input";
|
||||||
|
@ -28,7 +27,7 @@ interface Message {
|
||||||
user_type: string;
|
user_type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const API_URL = 'http://localhost:2058/host-api/app/v1/ticket/index.php';
|
const API_URL = 'http://192.168.1.197:2058/v1/ticket/index.php';
|
||||||
|
|
||||||
function Ticketing() {
|
function Ticketing() {
|
||||||
const [tickets, setTickets] = useState<Ticket[]>([]);
|
const [tickets, setTickets] = useState<Ticket[]>([]);
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./ui/card";
|
||||||
|
|
||||||
|
export default function TopicCreation(){
|
||||||
|
const API_URL = 'http://192.168.1.197:2058/v1/users/index.php';
|
||||||
|
// useEffect(() => {
|
||||||
|
// fetch(`${API_URL}?query=get-topic`)
|
||||||
|
// .then(response => response.json())
|
||||||
|
// .then{(data: any) => {
|
||||||
|
// console.log(data);
|
||||||
|
// }}
|
||||||
|
// })
|
||||||
|
return(
|
||||||
|
<>
|
||||||
|
<section className="container mx-auto px-4">
|
||||||
|
<div className="grid grid-cols md:grid-cols-2 lg:grid-cols-3">
|
||||||
|
<Card>
|
||||||
|
<CardContent>
|
||||||
|
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo, excepturi ipsum et animi debitis doloremque quam aliquid quaerat. Totam officiis iste laudantium amet corrupti, doloribus sunt minima dolor odit. Ipsum.
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import { Separator } from "./ui/separator";
|
||||||
import { Textarea } from "./ui/textarea";
|
import { Textarea } from "./ui/textarea";
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import UpdateAvatar from './UpdateAvatar';
|
import UpdateAvatar from './UpdateAvatar';
|
||||||
|
import {localizeTime} from "../lib/localizeTime";
|
||||||
|
|
||||||
interface SessionData {
|
interface SessionData {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
@ -24,13 +25,12 @@ export default function ProfilePage() {
|
||||||
const [userData, setUserData] = useState<UserData | null>(null);
|
const [userData, setUserData] = useState<UserData | null>(null);
|
||||||
const [invoiceList, setInvoiceList] = useState<any[]>([]);
|
const [invoiceList, setInvoiceList] = useState<any[]>([]);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const USER_API_URL = 'http://192.168.1.197:2058/v1/users/index.php';
|
||||||
|
const INVOICE_API_URL = 'http://192.168.1.197:2058/v1/invoice/';
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchSessionData = async () => {
|
const fetchSessionData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(`${USER_API_URL}?query=get-user`, {
|
||||||
'http://localhost:2058/host-api/v1/users/get-profile-data/',
|
|
||||||
{
|
|
||||||
credentials: 'include', // Crucial for cookies
|
credentials: 'include', // Crucial for cookies
|
||||||
headers: { 'Accept': 'application/json' }
|
headers: { 'Accept': 'application/json' }
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ export default function ProfilePage() {
|
||||||
};
|
};
|
||||||
const getInvoiceListData = async () => {
|
const getInvoiceListData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('http://localhost:2058/host-api/v1/invoice/invoice-info/', {
|
const response = await fetch(`${USER_API_URL}?query=invoice-info`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
credentials: 'include', // Crucial for cookies
|
credentials: 'include', // Crucial for cookies
|
||||||
headers: { 'Accept': 'application/json' }
|
headers: { 'Accept': 'application/json' }
|
||||||
|
@ -105,7 +105,6 @@ export default function ProfilePage() {
|
||||||
<AvatarFallback>JP</AvatarFallback>
|
<AvatarFallback>JP</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<UpdateAvatar />
|
<UpdateAvatar />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
|
@ -128,17 +127,22 @@ export default function ProfilePage() {
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="mt-6">
|
<Card className="mt-6">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex flex-row justify-between">
|
||||||
<CardTitle>Billing Information</CardTitle>
|
<CardTitle>Billing Information</CardTitle>
|
||||||
|
<a href="" className="hover:bg-[#6d9e37] hover:text-white transtion duration-500 py-1 px-2 rounded">View All</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
View your billing history.
|
View your billing history.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
<table className="w-full">
|
<table className="w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="text-left">Invoice ID</th>
|
<th className="text-left">Invoice</th>
|
||||||
<th className="text-left">Date</th>
|
<th className="text-left">Invoice Date</th>
|
||||||
<th className="text-left">Description</th>
|
<th className="text-left">Description</th>
|
||||||
<th className="text-right">Amount</th>
|
<th className="text-right">Amount</th>
|
||||||
|
<th className="text-right">Status</th>
|
||||||
<th className="text-center">Action</th>
|
<th className="text-center">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -146,11 +150,14 @@ export default function ProfilePage() {
|
||||||
{
|
{
|
||||||
invoiceList.map((invoice) => (
|
invoiceList.map((invoice) => (
|
||||||
<tr key={invoice.id}>
|
<tr key={invoice.id}>
|
||||||
<td>{invoice.invoice_id}</td>
|
<td>{invoice.invoice_number}</td>
|
||||||
<td>{invoice.date}</td>
|
<td>{invoice.invoice_date}</td>
|
||||||
<td>{invoice.description}</td>
|
<td>{invoice.notes ? invoice.notes : ''}</td>
|
||||||
<td className="text-right">{invoice.amount}</td>
|
<td className="text-right">{invoice.total_amount}</td>
|
||||||
<td className="text-center"><a href="">Print</a></td>
|
<td className="text-right">{invoice.status}</td>
|
||||||
|
<td className="text-center">
|
||||||
|
<a href="">View</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
import Layout from "../layouts/Layout.astro";
|
||||||
|
import MakePaymentPage from "../components/MakePayment";
|
||||||
|
---
|
||||||
|
<Layout title="">
|
||||||
|
<div>
|
||||||
|
<MakePaymentPage client:load />
|
||||||
|
</div>
|
||||||
|
</Layout>
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
import Layout from "../layouts/Layout.astro";
|
||||||
|
---
|
||||||
|
<Layout title="">
|
||||||
|
<div>
|
||||||
|
<h1>Payment Page</h1>
|
||||||
|
<h2>We are working on this!</h2>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
import Layout from "../layouts/Layout.astro";
|
||||||
|
import TestCools from "../components/TestCool";
|
||||||
|
---
|
||||||
|
<Layout title="">
|
||||||
|
<TestCools client:load />
|
||||||
|
</Layout>
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
import Layout from "../layouts/Layout.astro";
|
||||||
|
import TopicList from "../components/Topic";
|
||||||
|
---
|
||||||
|
<Layout title="">
|
||||||
|
<TopicList client:load />
|
||||||
|
</Layout>
|
40
yarn.lock
40
yarn.lock
|
@ -1919,7 +1919,7 @@ jiti@^1.21.6, jiti@>=1.21.0:
|
||||||
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz"
|
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz"
|
||||||
integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==
|
integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==
|
||||||
|
|
||||||
js-tokens@^4.0.0:
|
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
|
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
|
||||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||||
|
@ -1983,6 +1983,13 @@ longest-streak@^3.0.0:
|
||||||
resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz"
|
resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz"
|
||||||
integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==
|
integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==
|
||||||
|
|
||||||
|
loose-envify@^1.4.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
|
||||||
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
|
dependencies:
|
||||||
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
lru-cache@^10.2.0, lru-cache@^10.4.3:
|
lru-cache@^10.2.0, lru-cache@^10.4.3:
|
||||||
version "10.4.3"
|
version "10.4.3"
|
||||||
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz"
|
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz"
|
||||||
|
@ -2563,7 +2570,7 @@ npm-run-path@^5.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key "^4.0.0"
|
path-key "^4.0.0"
|
||||||
|
|
||||||
object-assign@^4.0.1:
|
object-assign@^4.0.1, object-assign@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
|
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
|
||||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||||
|
@ -2798,6 +2805,15 @@ prompts@^2.4.2:
|
||||||
kleur "^3.0.3"
|
kleur "^3.0.3"
|
||||||
sisteransi "^1.0.5"
|
sisteransi "^1.0.5"
|
||||||
|
|
||||||
|
prop-types@^15.8.1:
|
||||||
|
version "15.8.1"
|
||||||
|
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
|
||||||
|
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.4.0"
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
react-is "^16.13.1"
|
||||||
|
|
||||||
property-information@^6.0.0:
|
property-information@^6.0.0:
|
||||||
version "6.5.0"
|
version "6.5.0"
|
||||||
resolved "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz"
|
resolved "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz"
|
||||||
|
@ -2808,6 +2824,11 @@ property-information@^7.0.0:
|
||||||
resolved "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz"
|
resolved "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz"
|
||||||
integrity sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==
|
integrity sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==
|
||||||
|
|
||||||
|
qr.js@0.0.0:
|
||||||
|
version "0.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz"
|
||||||
|
integrity sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==
|
||||||
|
|
||||||
queue-microtask@^1.2.2:
|
queue-microtask@^1.2.2:
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
|
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
|
||||||
|
@ -2825,6 +2846,19 @@ radix3@^1.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
scheduler "^0.25.0"
|
scheduler "^0.25.0"
|
||||||
|
|
||||||
|
react-is@^16.13.1:
|
||||||
|
version "16.13.1"
|
||||||
|
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
|
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||||
|
|
||||||
|
react-qr-code@^2.0.15:
|
||||||
|
version "2.0.15"
|
||||||
|
resolved "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.15.tgz"
|
||||||
|
integrity sha512-MkZcjEXqVKqXEIMVE0mbcGgDpkfSdd8zhuzXEl9QzYeNcw8Hq2oVIzDLWuZN2PQBwM5PWjc2S31K8Q1UbcFMfw==
|
||||||
|
dependencies:
|
||||||
|
prop-types "^15.8.1"
|
||||||
|
qr.js "0.0.0"
|
||||||
|
|
||||||
react-refresh@^0.14.2:
|
react-refresh@^0.14.2:
|
||||||
version "0.14.2"
|
version "0.14.2"
|
||||||
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz"
|
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz"
|
||||||
|
@ -2879,7 +2913,7 @@ react-to-print@^3.0.5:
|
||||||
resolved "https://registry.npmjs.org/react-to-print/-/react-to-print-3.0.5.tgz"
|
resolved "https://registry.npmjs.org/react-to-print/-/react-to-print-3.0.5.tgz"
|
||||||
integrity sha512-Z15MwMOzYCHWi26CZeFNwflAg7Nr8uWD6FTj+EkfIOjYyjr0MXGbI0c7rF4Fgrbj3XG9hFndb1ourxpPz2RAiA==
|
integrity sha512-Z15MwMOzYCHWi26CZeFNwflAg7Nr8uWD6FTj+EkfIOjYyjr0MXGbI0c7rF4Fgrbj3XG9hFndb1ourxpPz2RAiA==
|
||||||
|
|
||||||
"react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ~19", "react@^17.0.2 || ^18.0.0 || ^19.0.0", react@^19.0.0, react@>=16.8.0, react@>=18:
|
react@*, "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ~19", "react@^17.0.2 || ^18.0.0 || ^19.0.0", react@^19.0.0, react@>=16.8.0, react@>=18:
|
||||||
version "19.0.0"
|
version "19.0.0"
|
||||||
resolved "https://registry.npmjs.org/react/-/react-19.0.0.tgz"
|
resolved "https://registry.npmjs.org/react/-/react-19.0.0.tgz"
|
||||||
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
|
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
|
||||||
|
|
Loading…
Reference in New Issue