| import React, { useState, useEffect } from 'react'; |
| import { useDispatch, useSelector } from 'react-redux'; |
| import { |
| fetchLinkedInAccounts, |
| initiateLinkedInAuth, |
| clearLinkedInError |
| } from '../../store/reducers/linkedinAccountsSlice'; |
| import LinkedInAccountCard from './LinkedInAccountCard'; |
|
|
| const LinkedInAccountsManager = () => { |
| const dispatch = useDispatch(); |
| const { |
| linkedinAccounts, |
| loading, |
| error, |
| oauthLoading, |
| oauthError |
| } = useSelector(state => { |
| console.log('π [DEBUG] LinkedInAccountsManager - Redux state:', state); |
| console.log('π [DEBUG] LinkedInAccountsManager - linkedinAccounts state:', state.linkedinAccounts); |
| return state.linkedinAccounts; |
| }); |
|
|
| const [showSuccess, setShowSuccess] = useState(false); |
|
|
| useEffect(() => { |
| console.log('π [DEBUG] LinkedInAccountsManager - useEffect triggered'); |
| console.log('π [DEBUG] LinkedInAccountsManager - Current state:', { linkedinAccounts, loading, error }); |
| dispatch(fetchLinkedInAccounts()); |
| }, [dispatch]); |
|
|
| useEffect(() => { |
| if (showSuccess) { |
| const timer = setTimeout(() => { |
| setShowSuccess(false); |
| }, 3000); |
| return () => clearTimeout(timer); |
| } |
| }, [showSuccess]); |
|
|
| const handleAddAccount = () => { |
| dispatch(clearLinkedInError()); |
| dispatch(initiateLinkedInAuth()); |
| }; |
|
|
| const handleRefreshAccounts = () => { |
| dispatch(fetchLinkedInAccounts()); |
| }; |
|
|
| const handleAccountLinked = () => { |
| setShowSuccess(true); |
| handleRefreshAccounts(); |
| }; |
|
|
| return ( |
| <div className="linkedin-accounts-manager"> |
| {/* Section Header */} |
| <div className="mb-6 sm:mb-8"> |
| <div className="flex items-center space-x-3 mb-3"> |
| <div className="w-10 h-10 sm:w-12 sm:h-12 bg-blue-100 rounded-xl flex items-center justify-center"> |
| <svg className="w-5 h-5 sm:w-6 sm:h-6 text-blue-600" fill="currentColor" viewBox="0 0 24 24"> |
| <path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.79M6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37h2.77z"/> |
| </svg> |
| </div> |
| <div> |
| <h2 className="text-xl sm:text-2xl font-bold text-gray-900">LinkedIn Accounts</h2> |
| <p className="text-sm sm:text-base text-gray-600"> |
| Manage your LinkedIn accounts for seamless content distribution |
| </p> |
| </div> |
| </div> |
| </div> |
| |
| {/* Success Message */} |
| {showSuccess && ( |
| <div className="mb-6 animate-fade-in"> |
| <div className="bg-green-50 border border-green-200 rounded-xl p-4 flex items-center space-x-3"> |
| <div className="flex-shrink-0"> |
| <svg className="w-5 h-5 text-green-400" fill="currentColor" viewBox="0 0 20 20"> |
| <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" /> |
| </svg> |
| </div> |
| <div className="flex-1"> |
| <p className="text-sm font-medium text-green-800">LinkedIn account linked successfully!</p> |
| </div> |
| </div> |
| </div> |
| )} |
| |
| {/* Error Messages */} |
| {oauthError && ( |
| <div className="mb-6 animate-fade-in"> |
| <div className="bg-red-50 border border-red-200 rounded-xl p-4 flex items-start space-x-3"> |
| <div className="flex-shrink-0"> |
| <svg className="w-5 h-5 text-red-400" fill="currentColor" viewBox="0 0 20 20"> |
| <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" /> |
| </svg> |
| </div> |
| <div className="flex-1"> |
| <p className="text-sm font-medium text-red-800">Failed to connect LinkedIn: {oauthError}</p> |
| </div> |
| </div> |
| </div> |
| )} |
| |
| {error && ( |
| <div className="mb-6 animate-fade-in"> |
| <div className="bg-red-50 border border-red-200 rounded-xl p-4 flex items-start space-x-3"> |
| <div className="flex-shrink-0"> |
| <svg className="w-5 h-5 text-red-400" fill="currentColor" viewBox="0 0 20 20"> |
| <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" /> |
| </svg> |
| </div> |
| <div className="flex-1"> |
| <p className="text-sm font-medium text-red-800">Error loading accounts: {error}</p> |
| </div> |
| </div> |
| </div> |
| )} |
| |
| {/* Action Buttons */} |
| <div className="flex flex-col sm:flex-row gap-3 sm:gap-4 mb-6 sm:mb-8"> |
| <button |
| onClick={handleAddAccount} |
| disabled={oauthLoading} |
| className="flex-1 sm:flex-none bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 disabled:from-blue-400 disabled:to-blue-500 text-white font-medium py-3 px-6 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-105 disabled:transform-none disabled:cursor-not-allowed flex items-center justify-center space-x-2" |
| > |
| {oauthLoading ? ( |
| <> |
| <svg className="animate-spin w-4 h-4" 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> |
| <span>Connecting...</span> |
| </> |
| ) : ( |
| <> |
| <svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"> |
| <path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.79M6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37h2.77z"/> |
| </svg> |
| <span>Add LinkedIn Account</span> |
| </> |
| )} |
| </button> |
| |
| <button |
| onClick={handleRefreshAccounts} |
| disabled={loading} |
| className="flex-1 sm:flex-none bg-white border border-gray-300 hover:border-gray-400 disabled:border-gray-200 disabled:bg-gray-50 text-gray-700 font-medium py-3 px-6 rounded-xl shadow-sm hover:shadow-md transition-all duration-300 transform hover:scale-105 disabled:transform-none disabled:cursor-not-allowed flex items-center justify-center space-x-2" |
| > |
| {loading ? ( |
| <> |
| <svg className="animate-spin w-4 h-4" 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> |
| <span>Refreshing...</span> |
| </> |
| ) : ( |
| <> |
| <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" /> |
| </svg> |
| <span>Refresh</span> |
| </> |
| )} |
| </button> |
| </div> |
|
|
| {} |
| <div className="accounts-list"> |
| {loading ? ( |
| <div className="flex flex-col items-center justify-center py-12 sm:py-16"> |
| <div className="animate-spin w-8 h-8 sm:w-12 sm:h-12 border-4 border-blue-200 border-t-blue-600 rounded-full mb-4"></div> |
| <p className="text-gray-600 text-sm sm:text-base font-medium">Loading LinkedIn accounts...</p> |
| </div> |
| ) : linkedinAccounts.length === 0 ? ( |
| <div className="text-center py-12 sm:py-16"> |
| <div className="w-16 h-16 sm:w-20 sm:h-20 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-6"> |
| <svg className="w-8 h-8 sm:w-10 sm:h-10 text-gray-400" fill="currentColor" viewBox="0 0 24 24"> |
| <path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.79M6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37h2.77z"/> |
| </svg> |
| </div> |
| <h3 className="text-lg sm:text-xl font-semibold text-gray-900 mb-3">No LinkedIn accounts connected</h3> |
| <p className="text-gray-600 mb-6 max-w-md mx-auto"> |
| Connect your LinkedIn account to start posting content and managing your social media presence |
| </p> |
| <button |
| onClick={handleAddAccount} |
| disabled={oauthLoading} |
| className="bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 disabled:from-blue-400 disabled:to-blue-500 text-white font-medium py-3 px-8 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-105 disabled:transform-none disabled:cursor-not-allowed inline-flex items-center space-x-2" |
| > |
| {oauthLoading ? ( |
| <> |
| <svg className="animate-spin w-4 h-4" 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> |
| <span>Connecting...</span> |
| </> |
| ) : ( |
| <> |
| <svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"> |
| <path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.79M6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37h2.77z"/> |
| </svg> |
| <span>Connect LinkedIn Account</span> |
| </> |
| )} |
| </button> |
| </div> |
| ) : ( |
| <> |
| <div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8"> |
| {linkedinAccounts.map((account) => ( |
| <LinkedInAccountCard |
| key={account.id} |
| account={account} |
| onRefresh={handleRefreshAccounts} |
| /> |
| ))} |
| </div> |
| |
| <div className="text-center py-8 border-t border-gray-200"> |
| <p className="text-gray-600 mb-4">Want to add another LinkedIn account?</p> |
| <button |
| onClick={handleAddAccount} |
| disabled={oauthLoading} |
| className="bg-white border border-gray-300 hover:border-gray-400 disabled:border-gray-200 disabled:bg-gray-50 text-gray-700 font-medium py-2 px-6 rounded-lg shadow-sm hover:shadow-md transition-all duration-300 inline-flex items-center space-x-2" |
| > |
| {oauthLoading ? ( |
| <> |
| <svg className="animate-spin w-4 h-4" 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> |
| <span>Connecting...</span> |
| </> |
| ) : ( |
| <> |
| <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" /> |
| </svg> |
| <span>+ Add Another Account</span> |
| </> |
| )} |
| </button> |
| </div> |
| </> |
| )} |
| </div> |
| </div> |
| ); |
| }; |
|
|
| export default LinkedInAccountsManager; |