diff --git a/app/components/AppNavigation.vue b/app/components/AppNavigation.vue index f7b1473..4d27e1a 100644 --- a/app/components/AppNavigation.vue +++ b/app/components/AppNavigation.vue @@ -112,7 +112,6 @@ const memberNavigationItems = [ { label: "Events", path: "/events" }, { label: "Members", path: "/members" }, { label: "Resources", path: "/resources" }, - { label: "Updates", path: "/updates" }, { label: "Peer Support", path: "/peer-support" }, { label: "Profile", path: "/member/profile" }, ]; diff --git a/app/components/PrivacyToggle.vue b/app/components/PrivacyToggle.vue index 8b0ca9a..597c87f 100644 --- a/app/components/PrivacyToggle.vue +++ b/app/components/PrivacyToggle.vue @@ -1,25 +1,22 @@ - - - - - - - - - @@ -816,16 +797,6 @@ const tabItems = [ slot: "profile", value: "profile", }, - { - label: "My Updates", - slot: "updates", - value: "updates", - }, - { - label: "Peer Support", - slot: "peer-support", - value: "peer-support", - }, { label: "Account", slot: "account", @@ -875,45 +846,54 @@ const formData = reactive({ avatar: "", studio: "", bio: "", - skills: [], location: "", - offering: "", - lookingFor: "", - socialLinks: { - mastodon: "", - linkedin: "", - website: "", - other: "", + offering: { + text: "", + tags: [], + }, + lookingFor: { + text: "", + tags: [], }, showInDirectory: true, + // Peer support fields + peerSupportEnabled: false, + peerSupportSkillTopics: [], + peerSupportSupportTopics: [], + peerSupportAvailability: "", + peerSupportMessage: "", + peerSupportSlackUsername: "", // Privacy settings pronounsPrivacy: "members", timeZonePrivacy: "members", - avatarPrivacy: "public", + avatarPrivacy: "members", studioPrivacy: "members", bioPrivacy: "members", - skillsPrivacy: "members", locationPrivacy: "members", offeringPrivacy: "members", lookingForPrivacy: "members", - socialLinksPrivacy: "members", }); -const currentSkillInput = ref(""); +// Tag input refs +const currentOfferingTagInput = ref(""); +const currentLookingForTagInput = ref(""); +const currentPeerSkillTopicInput = ref(""); + const loading = ref(false); const saving = ref(false); const saveSuccess = ref(false); const saveError = ref(null); const initialData = ref(null); -// Updates state -const myUpdates = ref([]); -const loadingUpdates = ref(false); -const loadingMoreUpdates = ref(false); -const hasMoreUpdates = ref(false); -const showDeleteUpdateModal = ref(false); -const updateToDelete = ref(null); -const deletingUpdate = ref(false); +// Available conversational support topics for peer support +const availableSupportTopics = [ + "Co-founder relationships", + "Burnout prevention", + "Impostor syndrome", + "Work-life boundaries", + "Conflict resolution", + "General chat & support", +]; // Account management state const contributionOptions = ref([]); @@ -944,18 +924,49 @@ const hasChanges = computed(() => { return JSON.stringify(formData) !== JSON.stringify(initialData.value); }); -// Add skill -const addSkill = () => { - const skill = currentSkillInput.value.trim().replace(/,$/, ""); - if (skill && !formData.skills.includes(skill)) { - formData.skills.push(skill); - currentSkillInput.value = ""; +// Offering tag management +const addOfferingTag = () => { + const tag = currentOfferingTagInput.value.trim().replace(/,$/, ""); + if (tag && !formData.offering.tags.includes(tag)) { + formData.offering.tags.push(tag); + currentOfferingTagInput.value = ""; } }; -// Remove skill -const removeSkill = (index) => { - formData.skills.splice(index, 1); +const removeOfferingTag = (index) => { + formData.offering.tags.splice(index, 1); +}; + +// Looking For tag management +const addLookingForTag = () => { + const tag = currentLookingForTagInput.value.trim().replace(/,$/, ""); + if (tag && !formData.lookingFor.tags.includes(tag)) { + formData.lookingFor.tags.push(tag); + currentLookingForTagInput.value = ""; + } +}; + +const removeLookingForTag = (index) => { + formData.lookingFor.tags.splice(index, 1); +}; + +// Peer support skill topic management +const addPeerSkillTopic = () => { + const topic = currentPeerSkillTopicInput.value.trim().replace(/,$/, ""); + if (topic && !formData.peerSupportSkillTopics.includes(topic)) { + formData.peerSupportSkillTopics.push(topic); + currentPeerSkillTopicInput.value = ""; + } +}; + +const removePeerSkillTopic = (index) => { + formData.peerSupportSkillTopics.splice(index, 1); +}; + +const addSuggestedSkillTopic = (tag) => { + if (!formData.peerSupportSkillTopics.includes(tag)) { + formData.peerSupportSkillTopics.push(tag); + } }; // Load member data @@ -967,30 +978,56 @@ const loadProfile = () => { formData.avatar = memberData.value.avatar || ""; formData.studio = memberData.value.studio || ""; formData.bio = memberData.value.bio || ""; - formData.skills = memberData.value.skills || []; formData.location = memberData.value.location || ""; - formData.offering = memberData.value.offering || ""; - formData.lookingFor = memberData.value.lookingFor || ""; - formData.socialLinks = memberData.value.socialLinks || { - mastodon: "", - linkedin: "", - website: "", - other: "", - }; + + // Load offering (handle both old string and new object format) + if (typeof memberData.value.offering === "string") { + formData.offering = { text: memberData.value.offering, tags: [] }; + } else { + formData.offering = { + text: memberData.value.offering?.text || "", + tags: memberData.value.offering?.tags || [], + }; + } + + // Load lookingFor (handle both old string and new object format) + if (typeof memberData.value.lookingFor === "string") { + formData.lookingFor = { text: memberData.value.lookingFor, tags: [] }; + } else { + formData.lookingFor = { + text: memberData.value.lookingFor?.text || "", + tags: memberData.value.lookingFor?.tags || [], + }; + } + formData.showInDirectory = memberData.value.showInDirectory ?? true; + // Load peer support data + if (memberData.value.peerSupport) { + formData.peerSupportEnabled = + memberData.value.peerSupport.enabled || false; + formData.peerSupportSkillTopics = + memberData.value.peerSupport.skillTopics || []; + formData.peerSupportSupportTopics = + memberData.value.peerSupport.supportTopics || []; + formData.peerSupportAvailability = + memberData.value.peerSupport.availability || ""; + formData.peerSupportMessage = + memberData.value.peerSupport.personalMessage || ""; + formData.peerSupportSlackUsername = + memberData.value.peerSupport.slackUsername || ""; + } + // Load privacy settings (with defaults) const privacy = memberData.value.privacy || {}; formData.pronounsPrivacy = privacy.pronouns || "members"; formData.timeZonePrivacy = privacy.timeZone || "members"; - formData.avatarPrivacy = privacy.avatar || "public"; + formData.avatarPrivacy = privacy.avatar || "members"; formData.studioPrivacy = privacy.studio || "members"; formData.bioPrivacy = privacy.bio || "members"; - formData.skillsPrivacy = privacy.skills || "members"; formData.locationPrivacy = privacy.location || "members"; formData.offeringPrivacy = privacy.offering || "members"; formData.lookingForPrivacy = privacy.lookingFor || "members"; - formData.socialLinksPrivacy = privacy.socialLinks || "members"; // Store initial state for change detection initialData.value = JSON.parse(JSON.stringify(formData)); @@ -1004,11 +1041,25 @@ const handleSubmit = async () => { saveError.value = null; try { + // Save profile data await $fetch("/api/members/profile", { method: "PATCH", body: formData, }); + // Save peer support data separately + await $fetch("/api/members/me/peer-support", { + method: "PATCH", + body: { + enabled: formData.peerSupportEnabled, + skillTopics: formData.peerSupportSkillTopics, + supportTopics: formData.peerSupportSupportTopics, + availability: formData.peerSupportAvailability, + personalMessage: formData.peerSupportMessage, + slackUsername: formData.peerSupportSlackUsername, + }, + }); + saveSuccess.value = true; // Refresh member data @@ -1035,78 +1086,6 @@ const resetForm = () => { saveError.value = null; }; -// Load user's updates -const loadUpdates = async () => { - if (!memberData.value?.id) return; - - loadingUpdates.value = true; - try { - const response = await $fetch(`/api/updates/user/${memberData.value.id}`, { - params: { limit: 20, skip: 0 }, - }); - myUpdates.value = response.updates; - hasMoreUpdates.value = response.hasMore; - } catch (error) { - console.error("Failed to load updates:", error); - } finally { - loadingUpdates.value = false; - } -}; - -// Load more updates -const loadMoreUpdates = async () => { - if (!memberData.value?.id) return; - - loadingMoreUpdates.value = true; - try { - const response = await $fetch(`/api/updates/user/${memberData.value.id}`, { - params: { limit: 20, skip: myUpdates.value.length }, - }); - myUpdates.value.push(...response.updates); - hasMoreUpdates.value = response.hasMore; - } catch (error) { - console.error("Failed to load more updates:", error); - } finally { - loadingMoreUpdates.value = false; - } -}; - -// Handle edit update -const handleEditUpdate = (update) => { - navigateTo(`/updates/${update._id}/edit`); -}; - -// Handle delete update -const handleDeleteUpdate = (update) => { - updateToDelete.value = update; - showDeleteUpdateModal.value = true; -}; - -// Confirm delete update -const confirmDeleteUpdate = async () => { - if (!updateToDelete.value) return; - - deletingUpdate.value = true; - try { - await $fetch(`/api/updates/${updateToDelete.value._id}`, { - method: "DELETE", - }); - - // Remove from list - myUpdates.value = myUpdates.value.filter( - (u) => u._id !== updateToDelete.value._id, - ); - - showDeleteUpdateModal.value = false; - updateToDelete.value = null; - } catch (error) { - console.error("Failed to delete update:", error); - alert("Failed to delete update. Please try again."); - } finally { - deletingUpdate.value = false; - } -}; - // Format date helper const formatDate = (dateString) => { if (!dateString) return ""; @@ -1334,7 +1313,6 @@ onMounted(async () => { } loadProfile(); - loadUpdates(); loadContributionOptions(); selectedContributionTier.value = memberData.value?.contributionTier || ""; }); @@ -1349,6 +1327,7 @@ useHead({ :deep(label) { color: rgb(231 229 228) !important; /* stone-200 */ font-weight: 500; + text-align: left !important; } /* Field descriptions - lighter gray for readability */ diff --git a/app/pages/member/settings/peer-support.vue b/app/pages/member/settings/peer-support.vue deleted file mode 100644 index 2dbd5e1..0000000 --- a/app/pages/member/settings/peer-support.vue +++ /dev/null @@ -1,366 +0,0 @@ - - - diff --git a/app/pages/members.vue b/app/pages/members.vue index eb84e64..272b9ca 100644 --- a/app/pages/members.vue +++ b/app/pages/members.vue @@ -34,13 +34,13 @@ -
+
Filter by skill: