addProfile.tsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // src/components/Onboarding.tsx
  2. 'use client'
  3. import { useState } from 'react';
  4. import { X, ArrowRight, Twitter, InstagramIcon, Facebook, Linkedin } from 'lucide-react';
  5. import { createProfile } from '@/lib/api/core';
  6. import { useTheme } from '@/contexts/themecontext';
  7. interface AddProfileProps {
  8. onComplete: () => void;
  9. }
  10. interface SocialInput {
  11. type: string;
  12. identifier: string;
  13. }
  14. export default function AddProfile({ onComplete }: AddProfileProps) {
  15. const { theme } = useTheme();
  16. const [step, setStep] = useState(1);
  17. const [profileName, setProfileName] = useState('');
  18. const [socials, setSocials] = useState<SocialInput[]>([]);
  19. const [error, setError] = useState('');
  20. const handleAddSocial = (type: string) => {
  21. setSocials([...socials, { type, identifier: '' }]);
  22. };
  23. const handleUpdateSocial = (index: number, identifier: string) => {
  24. const newSocials = [...socials];
  25. newSocials[index].identifier = identifier;
  26. setSocials(newSocials);
  27. };
  28. const handleRemoveSocial = (index: number) => {
  29. setSocials(socials.filter((_, i) => i !== index));
  30. };
  31. const handleSubmit = async () => {
  32. try {
  33. setError('');
  34. const workspaceId = localStorage.getItem('selectedWorkspaceId');
  35. if (!workspaceId) {
  36. setError('No workspace selected');
  37. return;
  38. }
  39. if (!profileName.trim()) {
  40. setError('Profile name is required');
  41. return;
  42. }
  43. // Filter out socials with empty identifiers
  44. const validSocials = socials.filter(s => s.identifier.trim() !== '');
  45. await createProfile({
  46. name: profileName.trim(),
  47. workspace_id: workspaceId,
  48. socials: validSocials
  49. });
  50. onComplete();
  51. } catch (error) {
  52. console.error('Failed to create profile:', error);
  53. setError('Failed to create profile. Please try again.');
  54. }
  55. };
  56. return (
  57. <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
  58. <div className={`${theme === 'dark' ? 'bg-gray-800' : 'bg-white'} rounded-lg shadow-xl max-w-md w-full p-6 relative`}>
  59. <button
  60. onClick={onComplete}
  61. className={`absolute top-4 right-4 p-1 rounded-full ${
  62. theme === 'dark' ? 'hover:bg-gray-700' : 'hover:bg-gray-100'
  63. }`}
  64. >
  65. <X className="w-5 h-5" />
  66. </button>
  67. <div className="mb-8">
  68. <h2 className={`text-xl font-semibold ${theme === 'dark' ? 'text-white' : 'text-gray-900'}`}>
  69. {step === 1 ? 'Ajouter un profil' : 'Ajouter des réseaux sociaux'}
  70. </h2>
  71. <div className="flex mt-4">
  72. <div className={`h-1 flex-1 rounded ${step === 1 ? 'bg-blue-500' : 'bg-gray-300'}`} />
  73. <div className={`h-1 flex-1 rounded ml-2 ${step === 2 ? 'bg-blue-500' : 'bg-gray-300'}`} />
  74. </div>
  75. </div>
  76. {error && (
  77. <div className="mb-4 p-3 bg-red-100 text-red-700 rounded-md">
  78. {error}
  79. </div>
  80. )}
  81. {step === 1 ? (
  82. <div>
  83. <div className="mb-6">
  84. <label className={`block text-sm font-medium ${theme === 'dark' ? 'text-gray-300' : 'text-gray-700'} mb-2`}>
  85. Nom du profil
  86. </label>
  87. <input
  88. type="text"
  89. value={profileName}
  90. onChange={(e) => setProfileName(e.target.value)}
  91. className={`w-full px-3 py-2 rounded-md border ${
  92. theme === 'dark'
  93. ? 'bg-gray-700 border-gray-600 text-white'
  94. : 'bg-white border-gray-300 text-gray-900'
  95. } focus:ring-2 focus:ring-blue-500 focus:border-transparent`}
  96. placeholder="Entrez le nom du profil"
  97. />
  98. </div>
  99. <button
  100. onClick={() => setStep(2)}
  101. disabled={!profileName.trim()}
  102. className={`w-full flex items-center justify-center px-4 py-2 rounded-md ${
  103. profileName.trim()
  104. ? 'bg-blue-500 hover:bg-blue-600 text-white'
  105. : 'bg-gray-300 text-gray-500 cursor-not-allowed'
  106. }`}
  107. >
  108. Suivant
  109. <ArrowRight className="w-4 h-4 ml-2" />
  110. </button>
  111. </div>
  112. ) : (
  113. <div>
  114. <div className="space-y-4 mb-6">
  115. {socials.map((social, index) => (
  116. <div key={index} className="flex items-center space-x-2">
  117. <input
  118. type="text"
  119. value={social.identifier}
  120. onChange={(e) => handleUpdateSocial(index, e.target.value)}
  121. className={`flex-1 px-3 py-2 rounded-md border ${
  122. theme === 'dark'
  123. ? 'bg-gray-700 border-gray-600 text-white'
  124. : 'bg-white border-gray-300 text-gray-900'
  125. } focus:ring-2 focus:ring-blue-500 focus:border-transparent`}
  126. placeholder={`Entrez l'identifiant ${social.type}`}
  127. />
  128. <button
  129. onClick={() => handleRemoveSocial(index)}
  130. className="p-2 text-red-500 hover:bg-red-100 rounded-md"
  131. >
  132. <X className="w-4 h-4" />
  133. </button>
  134. </div>
  135. ))}
  136. <div className="flex flex-wrap gap-2">
  137. {['twitter', 'instagram', 'facebook', 'linkedin'].filter(
  138. type => !socials.some(s => s.type === type)
  139. ).map((type) => (
  140. <button
  141. key={type}
  142. onClick={() => handleAddSocial(type)}
  143. className={`flex items-center px-3 py-2 rounded-md ${
  144. theme === 'dark'
  145. ? 'bg-gray-700 hover:bg-gray-600'
  146. : 'bg-gray-100 hover:bg-gray-200'
  147. }`}
  148. >
  149. {type === 'twitter' && <Twitter className="w-4 h-4 mr-2" />}
  150. {type === 'instagram' && <InstagramIcon className="w-4 h-4 mr-2" />}
  151. {type === 'facebook' && <Facebook className="w-4 h-4 mr-2" />}
  152. {type === 'linkedin' && <Linkedin className="w-4 h-4 mr-2" />}
  153. Ajouter {type.charAt(0).toUpperCase() + type.slice(1)}
  154. </button>
  155. ))}
  156. </div>
  157. </div>
  158. <div className="flex space-x-3">
  159. <button
  160. onClick={() => setStep(1)}
  161. className={`flex-1 px-4 py-2 rounded-md ${
  162. theme === 'dark'
  163. ? 'bg-gray-700 hover:bg-gray-600'
  164. : 'bg-gray-100 hover:bg-gray-200'
  165. }`}
  166. >
  167. Retour
  168. </button>
  169. <button
  170. onClick={handleSubmit}
  171. className="flex-1 px-4 py-2 rounded-md bg-blue-500 hover:bg-blue-600 text-white"
  172. >
  173. Créer le profil
  174. </button>
  175. </div>
  176. </div>
  177. )}
  178. </div>
  179. </div>
  180. );
  181. }