diff --git a/README.md b/README.md index e3b34c1..5736e2e 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,10 @@ The current KinTree project team as of Fall 2025 includes Andrea Ambrose, Matthe ### Prerequisites -Node.js (install the correct version for your own OS [here](https://nodejs.org/en)) and get your Supabase URL, CLIENT KEY, and SERVICE KEY from your project dashboard [here](https://supabase.com/) +Node.js (install the correct version for your own OS [here](https://nodejs.org/en)) +MySQL Install (https://dev.mysql.com/downloads/mysql/) -### Database Setup - -In the /server/ folder, add an .env file with variables `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY`. -In the /client/ folder, add an .env file with variables `REACT_APP_SUPABASE_URL` and `REACT_APP_SUPABASE_ANON_KEY`. - -### Web Application Setup +### Setup To set up the KinTree codebase on your own machine, start by cloning the repository to your local file system. @@ -39,3 +35,27 @@ Then, from the same directory, run the following command to run the server/API: `node server.js` +<<<<<<< Updated upstream +### Database Setup + +Open the MySQL Client Terminal, login with your password to run the mySQL server. + +Create a new database instance on your machine: +`CREATE DATABASE ` + +In the /server/ directory, create a .env file with MySQL information. Example env is in the project's /docs/ folder. + +Open another command line window in /SeniorProject_KinTree/server/ and run the command `npm install knex mysql2` to install Knex and mySQL2. + +Verify the connection: + +`node mysql-connection.js` + +Ensure proper migration files are loaded: + +`npx knex:migrate status` + +Run the command `npx knex migrate:latest` to create and/or update existing database tables. + +======= +>>>>>>> Stashed changes diff --git a/client/src/components/EditFamilyMember/EditFamilyMember.js b/client/src/components/EditFamilyMember/EditFamilyMember.js new file mode 100644 index 0000000..973011e --- /dev/null +++ b/client/src/components/EditFamilyMember/EditFamilyMember.js @@ -0,0 +1,341 @@ +import React, { useState, useEffect, useMemo } from 'react'; +import Popup from 'reactjs-popup'; +import 'reactjs-popup/dist/index.css'; +import { useForm } from 'react-hook-form'; +import * as styles from './styles'; +import './popup.css'; +import { ReactComponent as CloseIcon } from '../../assets/exit.svg'; +import { useCurrentUser } from '../../CurrentUserProvider'; +import { supabase } from '../../supabaseClient'; + +function EditFamilyMemberPopup({ trigger, memberId, onSaved }) { + const { currentUserID, currentAccountID } = useCurrentUser(); + + const [loading, setLoading] = useState(false); + const [view, setView] = useState('basic'); + const [relationshipData, setRelationshipData] = useState(null); + + const matPat = useMemo( + () => ['parent', 'cousin', 'aunt', 'uncle', 'grandparent', 'niece', 'nephew'], + [] + ); + + const { + register, + handleSubmit, + reset + } = useForm(); + + const { + register: registerRel, + handleSubmit: handleSubmitRel, + reset: resetRel, + watch: watchRel + } = useForm(); + + const selectedRelationship = watchRel('relationship'); + + useEffect(() => { + const loadMemberData = async () => { + if (!memberId) return; + + try { + setLoading(true); + + const { data: member, error: memberError } = await supabase + .from('family_members') + .select('*') + .eq('id', memberId) + .single(); + + if (memberError) throw memberError; + + const { data: relationship, error: relationshipError } = await supabase + .from('relationships') + .select('*') + .eq('person2_id', memberId) + .single(); + + if (relationshipError) throw relationshipError; + + setRelationshipData(relationship); + + reset({ + firstName: member.firstName || '', + lastName: member.lastName || '', + location: member.location || '', + birthday: member.birthDate || '', + birthplace: member.birthplace || '', + deathdate: member.deathDate || '' + }); + + resetRel({ + relationship: relationship.relationshipType || '', + matPat: relationship.side || '' + }); + } catch (err) { + console.error('Error loading family member:', err.message); + } finally { + setLoading(false); + } + }; + + loadMemberData(); + }, [memberId, reset, resetRel]); + + const closeModal = (close) => { + reset(); + resetRel(); + close(); + }; + + const onSubmitBasic = async (data) => { + try { + const { error } = await supabase + .from('family_members') + .update({ + firstName: data.firstName, + lastName: data.lastName, + location: data.location || null, + birthDate: data.birthday || null, + birthplace: data.birthplace || null, + deathDate: data.deathdate || null + }) + .eq('id', memberId); + + if (error) throw error; + + if (onSaved) onSaved(); + } catch (err) { + console.error('Error updating family member:', err.message); + } + }; + + const onSubmitRelationship = async (data) => { + try { + if (!relationshipData?.id) return; + + const { error } = await supabase + .from('relationships') + .update({ + person1_id: currentUserID, + person2_id: memberId, + relationshipType: data.relationship, + relationshipStatus: 'active', + side: matPat.includes(data.relationship) ? data.matPat : null, + userId: currentAccountID + }) + .eq('id', relationshipData.id); + + if (error) throw error; + + if (onSaved) onSaved(); + } catch (err) { + console.error('Error updating relationship:', err.message); + } + }; + + return ( + + {(close) => ( +
+ +
+ +
+ +

+ Edit Family Member +

+ + {loading ? ( +

Loading...

+ ) : ( + <> +
+ + + +
+ + {view === 'basic' && ( +
+
    +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + +
  • +
+ +
+ + + +
+
+ )} + + {view === 'relationship' && ( +
+
    +
  • + +
  • + + {matPat.includes(selectedRelationship) && ( +
  • + {' '} + Maternal + + {' '} + Paternal +
  • + )} +
+ +
+ + + +
+
+ )} + + )} +
+ )} +
+ ); +} + +export default EditFamilyMemberPopup; \ No newline at end of file diff --git a/client/src/components/EditFamilyMember/popup.css b/client/src/components/EditFamilyMember/popup.css new file mode 100644 index 0000000..c230a6a --- /dev/null +++ b/client/src/components/EditFamilyMember/popup.css @@ -0,0 +1,5 @@ +.popup-content { + width: auto; + border-radius: 30px; + min-width: 0px; +} \ No newline at end of file diff --git a/client/src/components/EditFamilyMember/styles.js b/client/src/components/EditFamilyMember/styles.js new file mode 100644 index 0000000..80059fe --- /dev/null +++ b/client/src/components/EditFamilyMember/styles.js @@ -0,0 +1,99 @@ +export const DefaultStyle = { + fontFamily: 'Alata', +}; + +export const FieldStyle = { + borderRadius: '5px', + border: '1px solid #000000', + marginLeft: '10px' +}; + +export const ListStyle = { + listStyleType: 'none', + fontFamily: 'Alata', + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-end', + marginRight: '15%' +}; + +export const ButtonDivStyle = { + fontFamily: 'Alata', + display: 'flex', + justifyContent: 'center', +} + +export const ButtonStyle = { + fontFamily: 'Alata', + backgroundColor: '#3a5a40', + color: 'white', + borderRadius: '20px', + border: 'none', + padding: '10px 30px', + margin: '10px', + cursor: 'pointer', +} + +export const GrayButtonStyle = { + fontFamily: 'Alata', + backgroundColor: '#D9D9D9', + color: 'black', + borderRadius: '20px', + border: 'none', + padding: '10px 20px', + margin: '10px', + cursor: 'pointer', + display: 'flex', + flexDirection: 'row', + boxShadow: 'gray 0px 10px 10px -8px', +} + +export const FormStyle = { + padding: '2vw', + paddingTop: '0px', + minWidth: '360px', +} + +export const ItemStyle = { + margin: '10px 0px' +} + +export const DateFieldStyle = { + borderRadius: '5px', + border: '1px solid #000000', + marginLeft: '10px', + width: '147px', + fontFamily: 'Alata' +}; + + +export const MainContainerStyle = { + display: 'flex', + flexDirection: 'column', + padding: '2vw', + paddingTop: '0px', + alignItems: 'center', + minWidth: '360px', + minHeight: '150px', + justifyContent: 'space-between', +} + +export const AddOptionsStyle = { + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + width: '90%', + padding: '10px', + fontFamily: 'Alata', + // border: '1px solid gray', + // borderRadius: '5px', + marginTop: '10px', + height: '200px', + overflow: 'auto' +} + +export const ListingStyle = { + padding: '10px', + border: '1px solid gray', + width: '90%' +} \ No newline at end of file diff --git a/client/src/components/Sync Contacts/Sync_Contacts_Button.js b/client/src/components/Sync Contacts/Sync_Contacts_Button.js new file mode 100644 index 0000000..01717e9 --- /dev/null +++ b/client/src/components/Sync Contacts/Sync_Contacts_Button.js @@ -0,0 +1,68 @@ +const handleSyncContacts = async () => { + try { + // 1. Ask for permission + const allow = window.confirm("Allow access to contacts?"); + if (!allow) { + alert("Permission denied. No contacts synced."); + return; + } + + // 2. Mock contacts (since browser can't access real ones) + const syncedContacts = [ + { + firstName: "John", + lastName: "Doe", + relationship: "sibling", + location: "New York", + birthday: "1995-05-10" + }, + { + firstName: "Jane", + lastName: "Smith", + relationship: "cousin", + location: "California", + birthday: "1998-08-22" + } + ]; + + console.log("Synced Contacts:", syncedContacts); + + // 3. OPTIONAL: send to backend + try { + await fetch("http://localhost:5000/api/contacts", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(syncedContacts) + }); + } catch (err) { + console.warn("Backend not connected, continuing..."); + } + + // 4. Auto-fill the first contact into your manual form + const firstContact = syncedContacts[0]; + + if (firstContact) { + // fill your react-hook-form fields + document.querySelector('input[name="firstName"]').value = firstContact.firstName; + document.querySelector('input[name="lastName"]').value = firstContact.lastName; + + const relationshipSelect = document.querySelector('select[name="relationship"]'); + if (relationshipSelect) relationshipSelect.value = firstContact.relationship; + + const locationInput = document.querySelector('input[name="location"]'); + if (locationInput) locationInput.value = firstContact.location; + + const birthdayInput = document.querySelector('input[name="birthday"]'); + if (birthdayInput) birthdayInput.value = firstContact.birthday; + } + + // 5. Feedback to user + alert("Contacts synced and form auto-filled!"); + + } catch (error) { + console.error("Error syncing contacts:", error); + alert("Something went wrong while syncing contacts."); + } +}; \ No newline at end of file diff --git a/client/src/utils/supabaseClient.js b/client/src/utils/supabaseClient.js index aafdeac..09f1c10 100644 --- a/client/src/utils/supabaseClient.js +++ b/client/src/utils/supabaseClient.js @@ -1,6 +1,6 @@ import { createClient } from '@supabase/supabase-js'; -const supabaseUrl = process.env.REACT_APP_SUPABASE_URL; -const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY; +const supabaseUrl = process.env.REACT_APP_SUPABASE_URL || 'https://bobchgtijgkxhaxfnvci.supabase.co/'; +const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJvYmNoZ3RpamdreGhheGZudmNpIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTk4NDk2OTMsImV4cCI6MjA3NTQyNTY5M30.3YH0lpoRH0lqKrj2TiOJSOPKhXDO7ULw9lPZeBkU3Bo'; export const supabase = createClient(supabaseUrl, supabaseAnonKey); diff --git a/docs/.env.example b/docs/.env.example index f25ad8d..2814bb3 100644 --- a/docs/.env.example +++ b/docs/.env.example @@ -1,7 +1,5 @@ -# SERVER ENV -SUPABASE_URL= -SUPABASE_SERVICE_ROLE_KEY= - -# CLIENT ENV -REACT_APP_SUPABASE_URL= -REACT_APP_SUPABASE_ANON_KEY= \ No newline at end of file +DB_HOST=localhost +DB_PORT=3306 +DB_USER=root +DB_PASSWORD=my_sql_password +DB_DATABASE=my_database_name diff --git a/server/controllers/authController.js b/server/controllers/authController.js index d161f0e..0a8ff6b 100644 --- a/server/controllers/authController.js +++ b/server/controllers/authController.js @@ -1,20 +1,136 @@ + // authController.js - the main backend file for user registration, signin, etc const User = require('../models/userModel'); // now backed by Supabase -const deleteByUser = async (req,res) => { +// authController.js +const bcrypt = require('bcryptjs'); +const User = require('../models/userModel'); +const FamilyMember = require('../models/familyMemberModel'); + + +const editByUser = async (req, res) => { + try { + const { id } = req.params; + const { username, email, password } = req.body; + + const user = await User.findById(id); + if (!user) { + return res.status(404).json({ error: 'User not found' }); + } + + const updatedFields = {}; + + if (username) updatedFields.username = username; + if (email) { + const existingUser = await User.findByEmail(email); + if (existingUser && existingUser.id !== parseInt(id)) { + return res.status(400).json({ error: 'Email already in use' }); + } + updatedFields.email = email; + } + if (password) { + const saltRounds = 12; + const salt = await bcrypt.genSalt(saltRounds); + const hashedPassword = await bcrypt.hash(password, salt); + updatedFields.password = hashedPassword; + } + + const updatedUser = await User.updateUser(id, updatedFields); + + res.status(200).json({ + message: 'User updated successfully', + user: updatedUser + }); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Error updating user' }); + } +}; + +async function deleteByUser(req, res) { + const { id } = req.params; + + try { + await User.deleteUser(id); + + res.json({ + message: "User deleted successfullyS" + }); + + } + catch (error) { + console.error(error); + res.status(500).json({error:"Error deleting user"}) + + + res.status(500).json({ + error: 'Registration failed' + }); + + } +}; + +const editByUser = async (req, res) => { + try { + const { id } = req.params; + const { name, relation, age, phone, email } = req.body; + + + const member = await FamilyMember.findById(id); + if (!member) { + return res.status(404).json({ error: "Family member not found" }); + } + + const updatedFields = {}; + + if (name) updatedFields.name = name; + if (relation) updatedFields.relation = relation; + if (age) updatedFields.age = age; + if (phone) updatedFields.phone = phone; + if (email) { + const emailOwner = await FamilyMember.findByEmail(email); + if (emailOwner && emailOwner.id != id) { + return res.status(400).json({ error: "Email already used by another member" }); + } + updatedFields.email = email; + } + + if (Object.keys(updatedFields).length === 0) { + return res.status(400).json({ error: "No valid fields provided to update" }); + } + + const updatedMember = await FamilyMember.updateFamilyMember(id, updatedFields); + + res.status(200).json({ + message: "Family member updated successfully", + familyMember: updatedMember + }); + + } catch (error) { + console.error(error); + res.status(500).json({ error: "Error updating family member" }); + } +}; + +async function deleteByUser(req, res) { const { id } = req.params; - try{ + try { await User.deleteUser(id); - res.json({ + res.json({ message: "User deleted successfullyS" - }) + }); } - catch (error){ + catch (error) { console.error(error); + + res.status(500); json({ error: "Error deleting user" }); + res.status(500).json({error:"Error deleting user"}) + + res.status(500); json({ error: "Error deleting user" }); } } @@ -56,26 +172,5 @@ const getAllUsers = async (req, res) => { } } -module.exports = { deleteByUser, findById, findByEmail, getAllUsers }; - -// Add a sync endpoint: POST /api/auth/sync -// Body: { auth_uid, email, username, firstName, lastName, phoneNumber, birthDate } -const syncAuthUser = async (req, res) => { - try { - const { auth_uid, email, username, firstName, lastName, phoneNumber, birthDate } = req.body || {}; - if (!auth_uid || !email) { - return res.status(400).json({ error: 'auth_uid and email are required' }); - } - const user = await User.upsertByAuthUser({ auth_uid, email, username, firstName, lastName, phoneNumber, birthDate }); - res.status(200).json(user); - } catch (error) { - console.error('Sync error:', error); - res.status(500).json({ - error: 'Error syncing auth user', - details: error.message, - stack: process.env.NODE_ENV === 'development' ? error.stack : undefined - }); - } -}; -module.exports.syncAuthUser = syncAuthUser; +module.exports = { register, login, editByUser, deleteByUser, findById, findByEmail, getAllUsers }; diff --git a/server/controllers/relationshipController.js b/server/controllers/relationshipController.js index 81db440..c131f9b 100644 --- a/server/controllers/relationshipController.js +++ b/server/controllers/relationshipController.js @@ -110,6 +110,66 @@ const addRelationship = async (req,res) =>{ } } +const editRelationship = async (req, res) => { + try { + const { id } = req.params; + const { person1_id, person2_id, relationshipType, relationshipStatus, side } = req.body; + + const relationship = await Relationship.findById(id); + if (!relationship) { + return res.status(404).json({ error: "Relationship not found" }); + } + + const updatedFields = {}; + + if (person1_id) updatedFields.person1_id = person1_id; + if (person2_id) updatedFields.person2_id = person2_id; + if (relationshipType) updatedFields.relationshipType = relationshipType; + if (relationshipStatus) updatedFields.relationshipStatus = relationshipStatus; + + if (side) { + if (!["paternal", "maternal", "both"].includes(side)) { + return res.status(400).json({ + error: "Invalid side. Must be 'paternal', 'maternal', or 'both'." + }); + } + updatedFields.side = side; + } + + if (Object.keys(updatedFields).length === 0) { + return res.status(400).json({ + error: "No valid fields provided to update" + }); + } + + + if (updatedFields.person1_id || updatedFields.person2_id) { + const person1 = updatedFields.person1_id || relationship.person1_id; + const person2 = updatedFields.person2_id || relationship.person2_id; + + const duplicate = await Relationship.findExisting(person1, person2); + if (duplicate && duplicate.id != id) { + return res.status(400).json({ + error: "A relationship with these people already exists" + }); + } + } + + + const updatedRelationship = await Relationship.updateRelationship(id, updatedFields); + + res.status(200).json({ + message: "Relationship updated successfully", + relationship: updatedRelationship + }); + + } catch (error) { + console.error(error); + res.status(500).json({ error: "Error updating relationship" }); + } +}; + + const filterBySide = async (req,res) => { try{ const {id} = req.params; @@ -151,6 +211,4 @@ const deleteByUser = async (req, res) => { } - - -module.exports = {getRelationships,getRelationshipsByUser,getRelationshipsByOtherUser, addRelationship, filterBySide, deleteByUser}; +module.exports = {getRelationships,getRelationshipsByUser, editRelationship, getRelationshipsByOtherUser, addRelationship, filterBySide, deleteByUser}; diff --git a/server/controllers/treeMemberController.js b/server/controllers/treeMemberController.js index c4af765..f6b562c 100644 --- a/server/controllers/treeMemberController.js +++ b/server/controllers/treeMemberController.js @@ -35,8 +35,7 @@ const addTreeMember = async (req, res) => { phoneNumber, userId: userIdInt, // Now guaranteed to be an integer memberUserId: memberUserIdInt // Now guaranteed to be an integer or null - }); - /// need to fix that a value can be left empty (deathDate) + });s // if there are relationships, add them to the database if (relationships && relationships.length > 0) { diff --git a/server/models/relationshipModel.js b/server/models/relationshipModel.js index 5f03682..e30c3ca 100644 --- a/server/models/relationshipModel.js +++ b/server/models/relationshipModel.js @@ -14,6 +14,7 @@ const Relationships = { side: data.side, userid: data.userId || data.userid, }; + // Remove undefined/null values Object.keys(mappedData).forEach(key => mappedData[key] === undefined && delete mappedData[key]); const { data: inserted, error } = await supabase @@ -24,6 +25,34 @@ const Relationships = { if (error) throw error; return inserted; }, + + updateRelationship: async (person1Id, person2Id, updates) => { + // Map camelCase fields to database column names + const mappedUpdates = { + person1_id: updates.person1_id || updates.person1Id, + person2_id: updates.person2_id || updates.person2Id, + relationshiptype: updates.relationshipType || updates.relationshiptype, + relationshipstatus: updates.relationshipStatus || updates.relationshipstatus, + side: updates.side, + userid: updates.userId || updates.userid, + }; + + // Remove undefined values so we only update what is provided + Object.keys(mappedUpdates).forEach( + key => mappedUpdates[key] === undefined && delete mappedUpdates[key] + ); + + const { data, error } = await supabase + .from('relationships') + .update(mappedUpdates) + .eq('person1_id', person1Id) + .eq('person2_id', person2Id) + .select('*') + .single(); + + if (error) throw error; + return data; + }, getRelationships: async (personId) => { // person1_id = personId OR person2_id = personId diff --git a/server/mysql-connection.js b/server/mysql-connection.js new file mode 100644 index 0000000..191170d --- /dev/null +++ b/server/mysql-connection.js @@ -0,0 +1,43 @@ +require('dotenv').config(); +const mysql = require('mysql2'); + +console.log('Database Config:', process.env.DB_USER, process.env.DB_PASSWORD, process.env.DB_DATABASE); + +const connection = mysql.createConnection({ + host: process.env.DB_HOST, // localhost + user: process.env.DB_USER, // Make sure DB_USER is set + password: process.env.DB_PASSWORD, // Ensure DB_PASSWORD is set + database: process.env.DB_DATABASE, // Ensure DB_DATABASE is set + port: process.env.DB_PORT || 3306 // Port should be 3306 +}); + +connection.connect((err) => { + if (err) { + console.error('Error connecting to MySQL:', err.stack); + return; + } + + console.log('Connected to MySQL as id ' + connection.threadId); + + // Example query to check connection + + connection.query('SELECT DATABASE()', (err, results) => { + if (err) { + console.error('Error running query:', err.stack); + return; + } + console.log('Connected to the database:', results[0]['DATABASE()']); + }); + + connection.query('SHOW DATABASES', (err, results) => { + if (err) { + console.error('Error fetching databases:', err); + } else { + console.log('Databases:', results.map(db => db.Database)); + } + connection.end(); // Close the connection + }); + + // Close the connection + connection.end(); +}); diff --git a/server/routes/authRoutes.js b/server/routes/authRoutes.js index 4b3636e..3b14b63 100644 --- a/server/routes/authRoutes.js +++ b/server/routes/authRoutes.js @@ -4,6 +4,13 @@ const router = express.Router(); const { deleteByUser, findByEmail, findById, getAllUsers, syncAuthUser } = require('../controllers/authController'); +const { register, login, editByUser, deleteByUser, findByEmail, findById, getAllUsers, } = require('../controllers/authController'); // Assuming you have a controller for your registration logic + +console.log('Register function:', register); + +router.post('/register', register); +router.post('/login', login); +router.patch('/edit/:id', editByUser); router.delete('/remove/:id', deleteByUser); router.get('/user/:id', findById); router.get('/user/email/:email', findByEmail); diff --git a/server/routes/contacts.js b/server/routes/contacts.js new file mode 100644 index 0000000..b176ff0 --- /dev/null +++ b/server/routes/contacts.js @@ -0,0 +1,28 @@ +const express = require("express"); +const router = express.Router(); + +// temporary storage (replace with DB later) +let contacts = []; + +// POST: save synced contacts +router.post("/", (req, res) => { + const newContacts = req.body; + + if (!newContacts || newContacts.length === 0) { + return res.status(400).json({ message: "No contacts provided" }); + } + + contacts = newContacts; + + res.status(200).json({ + message: "Contacts synced successfully", + data: contacts + }); +}); + +// GET: retrieve contacts +router.get("/", (req, res) => { + res.status(200).json(contacts); +}); + +module.exports = router; \ No newline at end of file diff --git a/server/routes/relationshipRoutes.js b/server/routes/relationshipRoutes.js index 3459277..21b6651 100644 --- a/server/routes/relationshipRoutes.js +++ b/server/routes/relationshipRoutes.js @@ -1,11 +1,12 @@ const express = require('express'); const router = express.Router(); -const { getRelationships, getRelationshipsByUser, getRelationshipsByOtherUser, addRelationship, filterBySide, deleteByUser} = require('../controllers/relationshipController'); +const { getRelationships, getRelationshipsByUser, editRelationship, getRelationshipsByOtherUser, addRelationship, filterBySide, deleteByUser} = require('../controllers/relationshipController'); router.post('/', addRelationship); router.get('/:id', getRelationships); router.get('/user/:id', getRelationshipsByUser); +router.patch('/relationship/edit/:id', editRelationship); router.get('/assignedUser/:id', getRelationshipsByOtherUser); router.get('/family-side/:id', filterBySide); router.delete('/remove/:id', deleteByUser); diff --git a/server/routes/treeMemberRoute.js b/server/routes/treeMemberRoute.js index 7c45829..5435d13 100644 --- a/server/routes/treeMemberRoute.js +++ b/server/routes/treeMemberRoute.js @@ -2,7 +2,7 @@ const express = require('express'); const router = express.Router(); -const { addTreeMember, editTreeMember,getMembersByUser, getMembersByOtherUser, deleteByUser, getMemberById, getActiveMemberId } = require('../controllers/treeMemberController'); +const { addTreeMember, editTreeMember,getMembersByUser, getMembersByOtherUser, deleteByUser, getMemberById, getActiveMemberId} = require('../controllers/treeMemberController'); router.post('/', addTreeMember); router.put('/:id', editTreeMember);