diff --git a/src/components/BuyServices/NewKubernetisUtho.jsx b/src/components/BuyServices/NewKubernetisUtho.jsx index b4611e9..c7e57a8 100644 --- a/src/components/BuyServices/NewKubernetisUtho.jsx +++ b/src/components/BuyServices/NewKubernetisUtho.jsx @@ -1,21 +1,27 @@ -import React, { useState, useEffect } from "react"; +import React, { useState } from "react"; import { Button } from '../ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"; import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "../ui/select"; import { Input } from "../ui/input"; import { Label } from "../ui/label"; -import Loader from "../ui/loader"; import { useToast } from "../ui/toast"; import { useIsLoggedIn } from '../../lib/isLoggedIn'; - +import Loader from "../ui/loader"; export default function Kubernetes() { - const { isLoggedIn, loading, balance } = useIsLoggedIn(); + // Environment variables and hooks + const PUBLIC_DEPLOYMENT_CHANEL_1_URL = import.meta.env.PUBLIC_DEPLOYMENT_CHANEL_1_URL; + const { loading, isLoggedIn, balance } = useIsLoggedIn(); const { showToast } = useToast(); + + // State management const [isLoading, setIsLoading] = useState(false); const [deployError, setDeployError] = useState(null); const [deployStatus, setDeployStatus] = useState({}); - const [clusterStatus, setClusterStatus] = useState(''); - const [productAmount, setProductAmount] = useState(100); + const [productAmount] = useState(100); + const [copied, setCopied] = useState(false); + const [downloadClusterId, setDownloadClusterId] = useState(''); + + // Form states const [nodePools, setNodePools] = useState([{ label: `${getRandomString()}`, size: '10215', @@ -28,7 +34,7 @@ export default function Kubernetes() { cluster_label: `${getRandomString()}`, }); - // Generate random string for IDs + // Helper functions function getRandomString(length = 8) { return Math.random().toString(36).substring(2, length+2); } @@ -40,58 +46,8 @@ export default function Kubernetes() { { id: '10218', name: '16 vCPU, 32GB RAM' } ]; - // Check cluster status periodically after deployment - useEffect(() => { - if (!deployStatus.clusterId || deployStatus.isReady) return; - - const checkStatus = async () => { - try { - const response = await fetch( - `https://host-api.cs1.hz.siliconpin.com/v1/kubernetis/?query=status&clusterId=${deployStatus.clusterId}&source=chanel_1`, - { credentials: "include" } - ); - - if (!response.ok) throw new Error("Failed to check status"); - - const data = await response.json(); - - // Update status - setClusterStatus(data.status || 'pending'); - - if (data.status === 'active') { - // Cluster is ready for configuration download - setDeployStatus(prev => ({ ...prev, isReady: true })); - showToast({ - title: "Cluster Ready", - description: "Your Kubernetes cluster is now fully configured.", - variant: "default" - }); - return; // Stop checking when ready - } else if (data.status === 'failed') { - throw new Error("Cluster deployment failed"); - } - - // Continue checking every 20 seconds if not ready - setTimeout(checkStatus, 20000); - } catch (error) { - console.error("Status check error:", error); - // Retry after delay if not a fatal error - if (!error.message.includes('failed')) { - setTimeout(checkStatus, 30000); - } else { - setDeployError(error.message); - } - } - }; - - const timer = setTimeout(checkStatus, 15000); - return () => clearTimeout(timer); - }, [deployStatus.clusterId, deployStatus.isReady]); - const handleSubmit = async (e) => { - if(balance < productAmount){ - return; - } + if (balance < productAmount) return; e.preventDefault(); setIsLoading(true); setDeployError(null); @@ -114,7 +70,7 @@ export default function Kubernetes() { }; const response = await fetch( - "https://host-api.cs1.hz.siliconpin.com/v1/kubernetis/?query=deploy&source=chanel_1", + `${PUBLIC_DEPLOYMENT_CHANEL_1_URL}kubernetis/?query=deploy&source=chanel_1`, { method: "POST", credentials: "include", @@ -130,13 +86,11 @@ export default function Kubernetes() { if (data.status === "success") { setDeployStatus({ status: "success", - clusterId: data.clusterId, - endpoint: data.endpoint, - isReady: false + clusterId: data.id }); showToast({ - title: "Deployment Started", - description: "Your cluster is being provisioned. This may take 10-15 minutes.", + title: "Deployment Successful", + description: "Your cluster is being provisioned.", variant: "default" }); } else { @@ -154,22 +108,26 @@ export default function Kubernetes() { } }; - const downloadKubeConfig = async () => { - if (!deployStatus.clusterId) return; - - try { - // Trigger download via backend - window.open( - `https://host-api.cs1.hz.siliconpin.com/v1/kubernetis/?query=download&clusterId=${deployStatus.clusterId}&source=chanel_1`, - '_blank' - ); - } catch (error) { + const downloadKubeConfig = (clusterId) => { + if (!clusterId) { showToast({ - title: "Download Failed", - description: "Could not download configuration. Please try again.", + title: "Cluster ID Required", + description: "Please enter a valid Cluster ID", variant: "destructive" }); + return; } + + window.open( + `${PUBLIC_DEPLOYMENT_CHANEL_1_URL}kubernetis/?query=download&clusterId=${clusterId}&source=chanel_1`, + '_blank' + ); + }; + + const handleCopy = (text) => { + navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 1000); }; // Form field handlers @@ -220,11 +178,9 @@ export default function Kubernetes() { setNodePools(updatedPools); } }; - if (loading) { return ; } - if (!isLoggedIn) { return (

@@ -235,248 +191,231 @@ export default function Kubernetes() { if (balance < productAmount) { return ( -

- You have insufficient balance to deploy this service. Please click here to go to your profile and add balance, then try again.

- ); - } - - if (deployStatus.status === 'success') { - return ( - - - Kubernetes Cluster Deployment - - {deployStatus.isReady - ? "Your cluster is ready to use" - : "Your cluster is being provisioned"} - - - -
- -
-
- {!deployStatus.isReady && } - - {deployStatus.isReady ? 'Ready' : (clusterStatus || 'Starting deployment')} - -
- {!deployStatus.isReady && ( -

- This process may take several minutes. Please don't close this page. -

- )} -
-
- -
-
- -

- {deployStatus.clusterId} -

-
-
- -

- {deployStatus.endpoint || 'Pending...'} -

-
-
- - {deployStatus.isReady ? ( -
- - -
- ) : ( -
- - Preparing your cluster... This may take several minutes -
- )} -
-
+

+ You have insufficient balance to deploy this service. Please click here to add balance. +

); } return ( - - - Create Kubernetes Cluster - - Configure your Kubernetes cluster with the desired specifications - - - -
-
-
- - + {/* Deployment Card */} + {deployStatus.status === 'success' ? ( + + + Kubernetes Cluster Deployment + Save your Cluster ID in a safe place to download configuration file + + +
+ +
+
+
+ ) : ( + + + Create Kubernetes Cluster + + Configure your Kubernetes cluster with the desired specifications + + + + +
+
+ + +
-
-
- - -
- - {nodePools.map((pool, poolIndex) => ( -
+
-

Node Pool #{poolIndex + 1}

- {nodePools.length > 1 && ( - - )} + +
-
-
- - handleNodePoolChange(poolIndex, 'label', e.target.value)} - placeholder="worker-pool" - /> -
+ {nodePools.map((pool, poolIndex) => ( +
+
+

Node Pool #{poolIndex + 1}

+ {nodePools.length > 1 && ( + + )} +
-
- - -
- -
- - handleNodePoolChange(poolIndex, 'count', parseInt(e.target.value) || 1)} - /> -
-
- -
-
- - -
- - {pool.ebs.map((disk, diskIndex) => ( -
+
- + handleDiskChange(poolIndex, diskIndex, 'disk', e.target.value)} - placeholder="30" + value={pool.label} + onChange={(e) => handleNodePoolChange(poolIndex, 'label', e.target.value)} + placeholder="worker-pool" />
- +
-
- {pool.ebs.length > 1 && ( - - )} +
+ + handleNodePoolChange(poolIndex, 'count', parseInt(e.target.value) || 1)} + />
- ))} -
-
- ))} -
-
-
- +
+
+ + +
+ + {pool.ebs.map((disk, diskIndex) => ( +
+
+ + handleDiskChange(poolIndex, diskIndex, 'disk', e.target.value)} + placeholder="30" + /> +
+ +
+ + +
+ +
+ {pool.ebs.length > 1 && ( + + )} +
+
+ ))} +
+
+ ))} +
+
+ +
+ +
+ + + + )} + + {/* Download Config Card - Always visible */} + + + Download Configuration + + Enter your Cluster ID to download the kubeconfig file
(Try to download config file after 5 minutes from Deployment!) +
+
+ +
+ + setDownloadClusterId(e.target.value)} + placeholder="Enter your Cluster ID" + />
- -
-
+ + + +
); } \ No newline at end of file diff --git a/src/components/CommentSystem/LikeSystem.jsx b/src/components/CommentSystem/LikeSystem.jsx new file mode 100644 index 0000000..1e9b174 --- /dev/null +++ b/src/components/CommentSystem/LikeSystem.jsx @@ -0,0 +1,98 @@ +import React, { useEffect, useState } from 'react'; +import { Heart, Loader2 } from 'lucide-react'; + +export default function LikeSystem({ postId, siliconId, token }) { + const [liked, setLiked] = useState(false); + const [likeCount, setLikeCount] = useState(0); + const [loading, setLoading] = useState(false); + + useEffect(() => { + const fetchLikeStatusAndCount = async () => { + try { + const countRes = await fetch(`https://sp-likes-pocndhvgmcnbacgb.siliconpin.com/posts/${postId}/likes`); + const countData = await countRes.json(); + setLikeCount(countData.likes); + + const likedRes = await fetch( + `https://sp-likes-pocndhvgmcnbacgb.siliconpin.com/is-liked?post_id=${postId}`, + { + headers: { + 'Authorization': `Bearer ${token}`, + 'X-SiliconId': siliconId, + }, + } + ); + const likedData = await likedRes.json(); + setLiked(likedData.liked); + } catch (err) { + console.error("Error fetching like data", err); + } + }; + + fetchLikeStatusAndCount(); + }, [postId, token, siliconId]); + + const handleLikeToggle = async () => { + setLoading(true); + try { + const res = await fetch(`https://sp-likes-pocndhvgmcnbacgb.siliconpin.com/like`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}`, + 'X-SiliconId': siliconId, + }, + body: JSON.stringify({ post_id: postId }), + }); + + const data = await res.json(); + if (data.success) { + setLiked(data.liked); + setLikeCount(prev => data.liked ? prev + 1 : prev - 1); + } + } catch (error) { + console.error('Network error:', error); + } finally { + setLoading(false); + } + }; + + return ( +
+ +
+ ); +} diff --git a/src/components/PaymentSuccessfully.jsx b/src/components/PaymentSuccessfully.jsx index b34464e..1ee889a 100644 --- a/src/components/PaymentSuccessfully.jsx +++ b/src/components/PaymentSuccessfully.jsx @@ -135,8 +135,8 @@ console.log('serviceName', serviceName) ) : ( <> -

VPN Credentials

-

⚠️ Make sure to save these credentials in a safe place. We do not store them.

+

VPN Credentials

+

Install WireGuard (Available on Android / IOS / Linux / Windows / FreeBSD) Scan this QR code using WireGuard app or import the config file.

) } @@ -148,7 +148,6 @@ console.log('serviceName', serviceName) {creds.qr_code && (
VPN Configuration QR Code -

Scan this QR code with your WireGuard app

)} @@ -161,6 +160,7 @@ console.log('serviceName', serviceName)
{creds.output}
+

⚠️ Make sure to save these credentials in a safe place. We do not store them.

)}
diff --git a/src/components/TopicDetail.jsx b/src/components/TopicDetail.jsx index e80c80c..5ed1c00 100644 --- a/src/components/TopicDetail.jsx +++ b/src/components/TopicDetail.jsx @@ -8,13 +8,16 @@ import { Button } from "./ui/button"; import { useIsLoggedIn } from '../lib/isLoggedIn'; import { token, user_name, pb_id } from '../lib/CookieValues'; import CommentSystem from './CommentSystem/CommentSystem'; -import '../styles/markdown.css' +import '../styles/markdown.css'; +import LikeSystem from './CommentSystem/LikeSystem' const COMMENTS_API_URL = 'https://host-api-sxashuasysagibx.siliconpin.com/v1/comments/'; export default function TopicDetail(props) { // console.log('coockie data', user_name) const [showCopied, setShowCopied] = useState(false); const [allGalleryImages, setAllGalleryImages] = useState([]); + const siliconId = '4uPRIGMm'; + const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJfcGJfdXNlcnNfYXV0aF8iLCJleHAiOjE3NTI5MjQxMTQsImlkIjoiZ203NzYyZ2Q2aTNscDAxIiwicmVmcmVzaGFibGUiOnRydWUsInR5cGUiOiJhdXRoIn0.Aq02zEAcXjyfsFO6MniM0atzzy2rSXx7B_rnilK6OYQ'; if (!props.topic) { return
Topic not found
; } @@ -126,10 +129,12 @@ export default function TopicDetail(props) {
{props.topic.title}

{props.topic.title}

- {/* Enhanced Social Share Buttons */}
-

Share this Topic:

+
+

Share this Topic:

+ +
- + {/* */} -

This will be used in the topic URL

+ {/*

This will be used in the topic URL

*/}
{/* Featured Image Upload */} diff --git a/src/pages/services/index.astro b/src/pages/services/index.astro index 8c4bf7a..12caeec 100644 --- a/src/pages/services/index.astro +++ b/src/pages/services/index.astro @@ -43,8 +43,8 @@ const services = [ { imageUrl: '/assets/images/services/kubernetes-edge.png', learnMoreUrl: '/services/kubernetes', - buyButtonText: '', - buyButtonUrl: '' + buyButtonText: 'Get K8s', + buyButtonUrl: '/services/kubernetes' }, { imageUrl: 'https://images.unsplash.com/photo-1558494949-ef010cbdcc31?q=80&w=2000&auto=format&fit=crop', @@ -233,7 +233,7 @@ const pageImage = "https://images.unsplash.com/photo-1551731409-43eb3e517a1a?q=8 newSchema1={JSON.stringify(schema1)} canonicalURL="/services" > -
+

Hosting Services