diff --git a/frontend/components/card/CardConnect.vue b/frontend/components/card/CardConnect.vue index ca33d89bb..2318dc262 100644 --- a/frontend/components/card/CardConnect.vue +++ b/frontend/components/card/CardConnect.vue @@ -60,6 +60,7 @@ }" > + + (); -const { userIsSignedIn } = useUser(); +// TODO: uncomment and delete 'true' line after issue 1006 is done. +// const { userIsSignedIn } = useUser(); +const userIsSignedIn = true; const paramsId = useRoute().params.id; const paramsGroupId = useRoute().params.groupId; @@ -158,13 +165,26 @@ const socialLinksRef = computed(() => { } }); -const toggleEditMode = () => { - editModeEnabled.value = !editModeEnabled.value; -}; +const handlePopupAddClick = async (payload: AddPayload, close: () => void) => { + // Put the social links payload in the database. + // TODO: Needs more robust handling (ie try/catch + error trapping/handling) + const response = await organizationStore.addSocialLinks( + organization, + payload + ); + if (response) { + console.log("org store addSocialLinks response: " + response); + console.log( + "CardConnect addSocialLinks payload: " + JSON.stringify(payload) + ); + } -const onClose = (close: (ref?: HTMLElement) => void) => { close(); }; +const toggleEditMode = () => { + editModeEnabled.value = !editModeEnabled.value; +}; + const emit = defineEmits(["on-new-account", "on-account-removed"]); diff --git a/frontend/components/popup/PopupNewField.vue b/frontend/components/popup/PopupNewField.vue index 91c3e72fd..de0982e2b 100644 --- a/frontend/components/popup/PopupNewField.vue +++ b/frontend/components/popup/PopupNewField.vue @@ -23,6 +23,7 @@ id="popup-input" class="focus-brand h-8 w-52 rounded-sm border border-primary-text bg-transparent p-2" type="text" + required :placeholder="fieldNamePrompt" /> @@ -43,14 +45,11 @@ cols="10" :placeholder="descriptionPrompt" > -
+
+ (); -const inputValue = ref(null); -const inputLabel = ref(null); +const emit = defineEmits(["add-clicked", "on-close-clicked"]); -const emit = defineEmits(["on-cta-clicked", "on-close-clicked"]); +const inputValue = ref(""); +const inputLabel = ref(""); + +const handleAddClick = () => { + // Validate user input and emit 'add' event + payload to CardConnect.vue. + // CardConnect.vue handles the data PUT's via the org store. + + if (!inputValue.value.trim()) { + alert("Please enter a 'Link to account'."); + return; + } + + // Super basic URL validation. URL has '.' and domain is 2 or more chars long. + const hasValidDomain = + inputValue.value.includes(".") && + inputValue.value.split(".")[1].length >= 2; + if (!hasValidDomain) { + alert(`${inputValue.value} is not a valid URL. Please enter a valid URL.`); + return; + } + + if (!inputLabel.value.trim()) { + alert("Please enter a 'Label for link'."); + return; + } + + emit("add-clicked", { + link: inputValue.value, + label: inputLabel.value, + }); +}; diff --git a/frontend/stores/organization.ts b/frontend/stores/organization.ts index 0efd86c94..30a0797bf 100644 --- a/frontend/stores/organization.ts +++ b/frontend/stores/organization.ts @@ -3,6 +3,7 @@ import type { OrganizationCreateFormData, OrganizationUpdateTextFormData, } from "~/types/entities/organization"; +import type { AddPayload } from "~/types/social-links-payload"; interface OrganizationStore { loading: boolean; @@ -54,7 +55,7 @@ export const useOrganizationStore = defineStore("organization", { const token = localStorage.getItem("accessToken"); const responseOrg = await useFetch( - `${BASE_BACKEND_URL}/entities/organizations/`, + `${BASE_BACKEND_URL as string}/entities/organizations/`, { method: "POST", body: JSON.stringify({ @@ -176,7 +177,7 @@ export const useOrganizationStore = defineStore("organization", { const token = localStorage.getItem("accessToken"); const responseOrg = await $fetch( - BASE_BACKEND_URL + `/entities/organizations/${org.id}/`, + (BASE_BACKEND_URL as string) + `/entities/organizations/${org.id}/`, { method: "PUT", body: { @@ -190,7 +191,7 @@ export const useOrganizationStore = defineStore("organization", { ); const responseOrgTexts = await $fetch( - BASE_BACKEND_URL + + (BASE_BACKEND_URL as string) + `/entities/organization_texts/${org.organizationTextId}/`, { method: "PUT", @@ -221,6 +222,46 @@ export const useOrganizationStore = defineStore("organization", { return false; }, + // MARK: Add Social Links + + async addSocialLinks(org: Organization, payload: AddPayload) { + // TODO: PUT/POST payload, PUT/POST org and social link id's in bridge table + // content/social_links + // TODO: Other PUT's/POST's? + // bridge table: organization_social_links + + this.loading = true; + + const token = localStorage.getItem("accessToken"); + + const responseSocialLinks = await useFetch( + `${BASE_BACKEND_URL as string}/content/social_links/${org.id}/`, + { + method: "PUT", + body: JSON.stringify({ + link: payload.link, + label: payload.label, + order: 0, + }), + headers: { + Authorization: `Token ${token}`, + }, + } + ); + + const responseSocialLinksData = responseSocialLinks.data + .value as unknown as Organization; + + if (responseSocialLinksData) { + this.loading = false; + + // return responseSocialLinksData.id; + return responseSocialLinksData; + } + + return false; + }, + // MARK: Delete async delete() { diff --git a/frontend/types/social-links-payload.ts b/frontend/types/social-links-payload.ts new file mode 100644 index 000000000..452c88470 --- /dev/null +++ b/frontend/types/social-links-payload.ts @@ -0,0 +1,4 @@ +export interface AddPayload { + link: string; + label: string; +}