From 9230fd8e4ed192b426e0d01495897cbfac9371ee Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 8 Oct 2025 10:36:57 +0000 Subject: [PATCH] connect to campaign graphql --- package-lock.json | 9 + package.json | 1 + src/pages/Settings.tsx | 477 +++++++++++++++++++++++++++++------------ 3 files changed, 349 insertions(+), 138 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1ddacb5..49911b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@apollo/client": "^4.0.7", + "@apollo/react-hooks": "^4.0.0", "@nhost/react": "^3.11.2", "graphql": "^16.11.0", "graphql-ws": "^6.0.6", @@ -89,6 +90,14 @@ } } }, + "node_modules/@apollo/react-hooks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-4.0.0.tgz", + "integrity": "sha512-fCu0cbne3gbUl0QbA8X4L33iuuFVQbC5Jo2MIKRK8CyawR6PoxDpFdFA1kc6033ODZuZZ9Eo4RdeJFlFIIYcLA==", + "dependencies": { + "@apollo/client": "latest" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", diff --git a/package.json b/package.json index 0ec8e99..176d6a7 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@apollo/client": "^4.0.7", + "@apollo/react-hooks": "^4.0.0", "@nhost/react": "^3.11.2", "graphql": "^16.11.0", "graphql-ws": "^6.0.6", diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index 783d43e..6081b89 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -1,8 +1,212 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import { gql } from '@apollo/client'; +import { useQuery, useMutation } from '@apollo/client/react'; + + + +import { useUserData, useAuthenticationStatus } from '@nhost/react'; + +// GraphQL Queries and Mutations +const GET_USER_PROFILE = gql` + + query GetUserProfile{ + user_profiles{ + id + display_name + created_at + metadata + } + } +`; + +const UPDATE_USER_PROFILE = gql` + mutation UpdateUserProfile($userId: uuid!, $displayName: String!, $metadata: jsonb) { + update_user_profiles_by_pk( + pk_columns: { id: $userId } + _set: { display_name: $displayName, metadata: $metadata } + ) { + id + display_name + metadata + } + } +`; + +const GET_USER_CAMPAIGNS = gql` + query GetUserCampaigns($userId: uuid!) { + campaigns(where: { user_id: { _eq: $userId } }) { + id + name + status + keywords_count + performance_metrics + created_at + updated_at + } + } +`; + +const CREATE_CAMPAIGN = gql` + mutation CreateCampaign($userId: uuid!, $name: String!, $keywords: jsonb) { + insert_campaigns_one(object: { + user_id: $userId, + name: $name, + keywords: $keywords, + status: "draft", + keywords_count: 0 + }) { + id + name + status + created_at + } + } +`; + +const UPDATE_CAMPAIGN = gql` + mutation UpdateCampaign($campaignId: uuid!, $name: String, $status: String) { + update_campaigns_by_pk( + pk_columns: { id: $campaignId } + _set: { name: $name, status: $status } + ) { + id + name + status + updated_at + } + } +`; + +const DELETE_CAMPAIGN = gql` + mutation DeleteCampaign($campaignId: uuid!) { + delete_campaigns_by_pk(id: $campaignId) { + id + name + } + } +`; const Settings = () => { const [activeSection, setActiveSection] = useState("profile"); const [activeSubSection, setActiveSubSection] = useState("payment-history"); + const [formData, setFormData] = useState({ + displayName: '', + email: '' + }); + + // NHost Authentication + const user = useUserData(); + const { isAuthenticated } = useAuthenticationStatus(); + + // GraphQL Queries + const { data: profileData, loading: profileLoading, refetch: refetchProfile } = useQuery(GET_USER_PROFILE, { + variables: { userId: user?.id }, + skip: !user?.id + }); + + const { data: campaignsData, loading: campaignsLoading, refetch: refetchCampaigns } = useQuery(GET_USER_CAMPAIGNS, { + variables: { userId: user?.id }, + skip: !user?.id + }); + + // GraphQL Mutations + const [updateUserProfile, { loading: updatingProfile }] = useMutation(UPDATE_USER_PROFILE); + const [createCampaign, { loading: creatingCampaign }] = useMutation(CREATE_CAMPAIGN); + const [updateCampaign] = useMutation(UPDATE_CAMPAIGN); + const [deleteCampaign] = useMutation(DELETE_CAMPAIGN); + + // Initialize form data when profile loads + useEffect(() => { + if (profileData?.user_profiles) { + const userProfile = profileData.user_profiles[0]; + setFormData({ + displayName: userProfile.display_name || '', + email: userProfile.email || '' + }); + } + }, [profileData]); + + const handleSectionClick = (sectionId: string) => { + setActiveSection(sectionId); + if (sectionId === "billing") { + setActiveSubSection("payment-history"); + } + }; + + const handleSubSectionClick = (subSection: string) => { + setActiveSubSection(subSection); + }; + + const handleInputChange = (field: string, value: string) => { + setFormData(prev => ({ + ...prev, + [field]: value + })); + }; + + const handleSaveProfile = async (e: React.FormEvent) => { + e.preventDefault(); + if (!user?.id) return; + + try { + await updateUserProfile({ + variables: { + userId: user.id, + displayName: formData.displayName, + metadata: { last_updated: new Date().toISOString() } + } + }); + await refetchProfile(); + // You can add a toast notification here for success + } catch (error) { + console.error('Error updating profile:', error); + // Handle error (show toast, etc.) + } + }; + + const handleCreateCampaign = async () => { + if (!user?.id) return; + + try { + await createCampaign({ + variables: { + userId: user.id, + name: `New Campaign ${new Date().toLocaleDateString()}`, + keywords: [] + } + }); + await refetchCampaigns(); + } catch (error) { + console.error('Error creating campaign:', error); + } + }; + + const handleUpdateCampaign = async (campaignId: string, updates: { name?: string; status?: string }) => { + try { + await updateCampaign({ + variables: { + campaignId, + ...updates + } + }); + await refetchCampaigns(); + } catch (error) { + console.error('Error updating campaign:', error); + } + }; + + const handleDeleteCampaign = async (campaignId: string) => { + if (!confirm('Are you sure you want to delete this campaign?')) return; + + try { + await deleteCampaign({ + variables: { campaignId } + }); + await refetchCampaigns(); + } catch (error) { + console.error('Error deleting campaign:', error); + } + }; const sidebarItems = [ { @@ -66,111 +270,105 @@ const Settings = () => { } ]; - const handleSectionClick = (sectionId: string) => { - setActiveSection(sectionId); - if (sectionId === "billing") { - setActiveSubSection("payment-history"); - } - }; - - const handleSubSectionClick = (subSection: string) => { - setActiveSubSection(subSection); - }; + if (!isAuthenticated) { + return ( +
+
+

Please log in to access settings

+
+
+ ); + } return ( -
-
- {/* Sidebar */} -
-

Settings

- - +
- {/* Main Content */} -
- {activeSection === "profile" && ( -
-

Basic Information

-

- View and update your personal details and account information. -

+ {/* Main Content */} +
+ {activeSection === "profile" && ( +
+

Basic Information

+

+ View and update your personal details and account information. +

-
+ {profileLoading ? ( +
Loading profile...
+ ) : ( +
handleInputChange('displayName', e.target.value)} className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
-
+ {/*
-
- -
- - -
+

Email cannot be changed

+
*/}
-
- -
- -
-
- )} + )} +
+ )} - {activeSection === "campaigns" && ( -
-
-
-

Campaigns

-

- Manage your keyword campaigns and track performance. -

-
- + {activeSection === "campaigns" && ( +
+
+
+

Campaigns

+

+ Manage your keyword campaigns and track performance. +

+ +
+ {campaignsLoading ? ( +
Loading campaigns...
+ ) : (
- {[ - { name: "Summer Sale 2025", keywords: 127, status: "Active", performance: "+12.5%" }, - { name: "Product Launch Q3", keywords: 89, status: "Active", performance: "+8.3%" }, - { name: "Brand Awareness", keywords: 234, status: "Paused", performance: "+5.2%" }, - { name: "Holiday Campaign", keywords: 156, status: "Active", performance: "+15.7%" }, - ].map((campaign, index) => ( -
+ {campaignsData?.campaigns?.map((campaign: any) => ( +

{campaign.name}

{campaign.status}
- {campaign.keywords} keywords - - Performance: - {campaign.performance} - + {campaign.keywords_count || 0} keywords + Created: {new Date(campaign.created_at).toLocaleDateString()}
- -
))} + + {(!campaignsData?.campaigns || campaignsData.campaigns.length === 0) && ( +
+ No campaigns found. Create your first campaign! +
+ )}
-
- )} -
+ )} +
+ )}
+
); };