From dce34afebae3c72e72b1c694ffe04d490fe1fb93 Mon Sep 17 00:00:00 2001 From: Kyle Zarazan Date: Fri, 22 Nov 2024 16:06:43 -0700 Subject: [PATCH] add action cable updates --- app/channels/application_cable/channel.rb | 4 ++ app/channels/application_cable/connection.rb | 4 ++ app/channels/recipe_channel.rb | 8 ++++ app/controllers/recipes_controller.rb | 9 ++++ app/javascript/application.tsx | 1 - app/javascript/channels/consumer.ts | 5 +++ app/javascript/channels/recipe_channel.ts | 21 ++++++++++ app/javascript/components/App.tsx | 2 + .../components/recipes/RecipeEdit.tsx | 41 +++++++++++++++---- .../components/recipes/RecipeForm.tsx | 2 +- app/javascript/store/recipesSlice.ts | 35 +++++++++++++++- app/models/recipe.rb | 19 ++++++++- config/environments/development.rb | 5 +++ config/routes.rb | 2 +- package-lock.json | 41 +++++++++++++++++++ package.json | 3 ++ 16 files changed, 189 insertions(+), 13 deletions(-) create mode 100644 app/channels/application_cable/channel.rb create mode 100644 app/channels/application_cable/connection.rb create mode 100644 app/channels/recipe_channel.rb create mode 100644 app/javascript/channels/consumer.ts create mode 100644 app/javascript/channels/recipe_channel.ts diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/channels/recipe_channel.rb b/app/channels/recipe_channel.rb new file mode 100644 index 0000000..6fb6df7 --- /dev/null +++ b/app/channels/recipe_channel.rb @@ -0,0 +1,8 @@ +class RecipeChannel < ApplicationCable::Channel + def subscribed + stream_from "recipe_channel" + end + + def unsubscribed + end +end diff --git a/app/controllers/recipes_controller.rb b/app/controllers/recipes_controller.rb index 604cee4..cbe6912 100644 --- a/app/controllers/recipes_controller.rb +++ b/app/controllers/recipes_controller.rb @@ -22,6 +22,15 @@ def update end end + def destroy + @recipe = Recipe.find(params[:id]) + if @recipe.destroy + render :create, status: :ok + else + render :errors, status: :unprocessable_entity + end + end + private def recipe_params diff --git a/app/javascript/application.tsx b/app/javascript/application.tsx index c96f008..c4e002b 100644 --- a/app/javascript/application.tsx +++ b/app/javascript/application.tsx @@ -1,7 +1,6 @@ import React from "react"; import * as ReactDOM from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; - import App from "./components/App"; ReactDOM.createRoot(document.getElementById("app")!).render( diff --git a/app/javascript/channels/consumer.ts b/app/javascript/channels/consumer.ts new file mode 100644 index 0000000..b1d32a1 --- /dev/null +++ b/app/javascript/channels/consumer.ts @@ -0,0 +1,5 @@ +import { createConsumer } from "@rails/actioncable" + +const consumer = createConsumer() + +export default consumer diff --git a/app/javascript/channels/recipe_channel.ts b/app/javascript/channels/recipe_channel.ts new file mode 100644 index 0000000..3752814 --- /dev/null +++ b/app/javascript/channels/recipe_channel.ts @@ -0,0 +1,21 @@ + +import { store } from "../store/store" +import { recipeUpdated } from "../store/recipesSlice" +import consumer from "./consumer" + +consumer.subscriptions.create("RecipeChannel", { + connected() { + console.log("Connected to RecipeChannel") + }, + + disconnected() { + console.log("Disconnected from RecipeChannel") + }, + + received(data) { + if (data.type === 'RECIPE_UPDATED') { + console.log("Received recipe update:", data.recipe) + store.dispatch(recipeUpdated(data.recipe)) + } + } +}) diff --git a/app/javascript/components/App.tsx b/app/javascript/components/App.tsx index fdf2fc6..4567060 100644 --- a/app/javascript/components/App.tsx +++ b/app/javascript/components/App.tsx @@ -11,6 +11,8 @@ import Foods from "./foods/FoodsIndex"; import NewRecipeForm from './recipes/RecipeNew'; import RecipeEdit from './recipes/RecipeEdit'; +import "../channels/recipe_channel" + const App: React.FC = () => { return ( diff --git a/app/javascript/components/recipes/RecipeEdit.tsx b/app/javascript/components/recipes/RecipeEdit.tsx index 1475f7c..229ce04 100644 --- a/app/javascript/components/recipes/RecipeEdit.tsx +++ b/app/javascript/components/recipes/RecipeEdit.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; -import { updateRecipe } from '../../store/recipesSlice'; +import { updateRecipe, deleteRecipe } from '../../store/recipesSlice'; import { RecipeFormData } from './RecipeForm'; import useCsrfToken from '../../hooks/useCsrfToken'; import { useNavigate, useParams } from 'react-router-dom'; @@ -51,17 +51,44 @@ const EditRecipeForm: React.FC = () => { }); }; + const handleDelete = () => { + if (window.confirm('Are you sure you want to delete this recipe? This action cannot be undone.')) { + dispatch(deleteRecipe({ + id: Number(id), + csrfToken + })) + .unwrap() + .then(() => { + navigate('/recipes'); + }) + .catch((error: Error) => { + alert('Failed to delete recipe: ' + error.message); + }); + } + }; + if (!recipe) { return
Recipe not found
; } return ( - +
+

Edit Recipe

+ +
+ +
+
); }; diff --git a/app/javascript/components/recipes/RecipeForm.tsx b/app/javascript/components/recipes/RecipeForm.tsx index b3d027f..1c6ba65 100644 --- a/app/javascript/components/recipes/RecipeForm.tsx +++ b/app/javascript/components/recipes/RecipeForm.tsx @@ -76,7 +76,7 @@ const RecipeForm: React.FC = ({ formData, setFormData, onSubmit