Gcobani Mkontwana

Gcobani Mkontwana

  • 955
  • 817
  • 993

How to make front end interact with back end?

Oct 20 2024 3:36 AM

Hi Team

I have a mean stack app, basically my front end suppose when type 'wine or vintage' as search field name must return or fetch data back to front end. Now the response when debugging its receving this data back;

 

(index):68 Uncaught (in promise) TypeError: wines.filter is not a function
    at fetchWines ((index):68:37)

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import 'bootstrap/dist/css/bootstrap.min.css';
import '@fortawesome/fontawesome-free/css/all.min.css';
import './App.css';

const App: React.FC = () => {
  const [wines, setWines] = useState<any[]>([]);
  const [criteria, setCriteria] = useState('revenue');
  const [searchTerm, setSearchTerm] = useState('');

  useEffect(() => {
    const fetchWines = async () => {
      try {
        const response = await axios.get(
          `/api/best-selling-wines?criteria=${criteria}&searchTerm=${searchTerm}`,
          {
            headers: { 'Cache-Control': 'no-cache' },
          }
        );
        console.log('Response:', response);
        console.log('Response data:', response.data);
        if (response.headers['content-type'].includes('application/json')) {
          const winesData = response.data.bestSellingWines;
          console.log('Best Selling Wines:', winesData);
          setWines(Array.isArray(winesData) ? winesData : []);
        } else {
          console.error('Unexpected response:', response.data);
        }
      } catch (error) {
        if (axios.isAxiosError(error)) {
          console.error('Error fetching data:', error.response ? error.response.data : error.message);
        } else {
          console.error('Unexpected error:', error);
        }
      }
    };

    fetchWines();
  }, [criteria, searchTerm]);

  const filteredWines = Array.isArray(wines)
    ? wines.filter(
        (wine) =>
          wine.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
          wine.vintage?.toString().includes(searchTerm)
      )
    : [];

  return (
    <div className="container">
      <nav className="navbar navbar-expand-lg navbar-light bg-light">
        <a className="navbar-brand" >
          Wine Stats
        </a>
        <div className="collapse navbar-collapse" id="navbarNav">
          <ul className="navbar-nav">
            <li className="nav-item">
              <button className="nav-link btn" onClick={() => setCriteria('revenue')}>
                By Revenue
              </button>
            </li>
            <li className="nav-item">
              <button className="nav-link btn" onClick={() => setCriteria('quantity')}>
                By # Bottles Sold
              </button>
            </li>
            <li className="nav-item">
              <button className="nav-link btn" onClick={() => setCriteria('orders')}>
                By Orders
              </button>
            </li>
          </ul>
        </div>
      </nav>
      <h1 className="mt-4 text-center">Best Selling Wines</h1>
      <div className="search-bar-container">
        <div className="search-bar">
          <input
            id="searchBar"
            type="text"
            className="form-control"
            placeholder="Search by name or vintage..."
            value={searchTerm}
            onChange={(e) => setSearchTerm(e.target.value)}
          />
          <span className="search-icon">
            <i className="fas fa-search"></i>
          </span>
        </div>
      </div>
      <table className="table mt-3">
        <thead>
          <tr>
            <th>Rank</th>
            <th>Wine Name</th>
            <th>Vintage</th>
            <th>Revenue</th>
          </tr>
        </thead>
        <tbody>
          {filteredWines.map((wine) => (
            <tr
              key={wine.masterWineId}
              className={wine.isTop10 ? 'table-success' : wine.isBottom10 ? 'table-danger' : ''}
            >
              <td>{wine.rank}</td>
              <td>{wine.name}</td>
              <td>{wine.vintage}</td>
              <td>GBP {wine.revenue.toFixed(2)}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default App;

//back end response




      isTop10: true,
      isBottom10: false
    },
    {
      masterWineId: 2,
      name: 'Domaine Leflaive',
      vintage: 2018,
      revenue: 240,
      quantity: 2,
      orders: 1,
      price: 120,
      rank: 2,
      isTop10: false,
      isBottom10: false
    },
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 203.8,
      quantity: 5,
      orders: 1,
      price: 40.76,
      rank: 3,
      isTop10: false,
      isBottom10: false
    }
  ],
  masterWines: [
    { id: 1, name: 'Château Montclair', vintage: 2020 },  
    { id: 2, name: 'Domaine Leflaive', vintage: 2018 },   
    { id: 1, name: 'Château Montclair', vintage: 2020 }   
  ]
}
Incoming request: [Object: null prototype] { criteria: 'revenue' }
Wines data: {
  bestSellingWines: [
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 402.6,
      quantity: 10,
      orders: 1,
      price: 40.26,
      rank: 1,
      isTop10: true,
      isBottom10: false
    },
    {
      masterWineId: 2,
      name: 'Domaine Leflaive',
      vintage: 2018,
      revenue: 240,
      quantity: 2,
      orders: 1,
      price: 120,
      rank: 2,
      isTop10: false,
      isBottom10: false
    },
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 203.8,
      quantity: 5,
      orders: 1,
      price: 40.76,
      rank: 3,
      isTop10: false,
      isBottom10: false
    }
  ],
  masterWines: [
    { id: 1, name: 'Château Montclair', vintage: 2020 },  
    { id: 2, name: 'Domaine Leflaive', vintage: 2018 },   
    { id: 1, name: 'Château Montclair', vintage: 2020 }   
  ]
}
Incoming request: [Object: null prototype] { criteria: 'revenue' }
Wines data: {
  bestSellingWines: [
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 402.6,
      quantity: 10,
      orders: 1,
      price: 40.26,
      rank: 1,
      isTop10: true,
      isBottom10: false
    },
    {
      masterWineId: 2,
      name: 'Domaine Leflaive',
      vintage: 2018,
      revenue: 240,
      quantity: 2,
      orders: 1,
      price: 120,
      rank: 2,
      isTop10: false,
      isBottom10: false
    },
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 203.8,
      quantity: 5,
      orders: 1,
      price: 40.76,
      rank: 3,
      isTop10: false,
      isBottom10: false
    }
  ],
  masterWines: [
    { id: 1, name: 'Château Montclair', vintage: 2020 },  
    { id: 2, name: 'Domaine Leflaive', vintage: 2018 },   
    { id: 1, name: 'Château Montclair', vintage: 2020 }   
  ]
}
Incoming request: [Object: null prototype] { criteria: 'revenue' }
Wines data: {
  bestSellingWines: [
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 402.6,
      quantity: 10,
      orders: 1,
      price: 40.26,
      rank: 1,
      isTop10: true,
      isBottom10: false
    },
    {
      masterWineId: 2,
      name: 'Domaine Leflaive',
      vintage: 2018,
      revenue: 240,
      quantity: 2,
      orders: 1,
      price: 120,
      rank: 2,
      isTop10: false,
      isBottom10: false
    },
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 203.8,
      quantity: 5,
      orders: 1,
      price: 40.76,
      rank: 3,
      isTop10: false,
      isBottom10: false
    }
  ],
  masterWines: [
    { id: 1, name: 'Château Montclair', vintage: 2020 },  
    { id: 2, name: 'Domaine Leflaive', vintage: 2018 },   
    { id: 1, name: 'Château Montclair', vintage: 2020 }   
  ]
}
Incoming request: [Object: null prototype] { criteria: 'revenue' }
Wines data: {
  bestSellingWines: [
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 402.6,
      quantity: 10,
      orders: 1,
      price: 40.26,
      rank: 1,
      isTop10: true,
      isBottom10: false
    },
    {
      masterWineId: 2,
      name: 'Domaine Leflaive',
      vintage: 2018,
      revenue: 240,
      quantity: 2,
      orders: 1,
      price: 120,
      rank: 2,
      isTop10: false,
      isBottom10: false
    },
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 203.8,
      quantity: 5,
      orders: 1,
      price: 40.76,
      rank: 3,
      isTop10: false,
      isBottom10: false
    }
  ],
  masterWines: [
    { id: 1, name: 'Château Montclair', vintage: 2020 },  
    { id: 2, name: 'Domaine Leflaive', vintage: 2018 },   
    { id: 1, name: 'Château Montclair', vintage: 2020 }   
  ]
}
Incoming request: [Object: null prototype] { criteria: 'revenue' }
Wines data: {
  bestSellingWines: [
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 402.6,
      quantity: 10,
      orders: 1,
      price: 40.26,
      rank: 1,
      isTop10: true,
      isBottom10: false
    },
    {
      masterWineId: 2,
      name: 'Domaine Leflaive',
      vintage: 2018,
      revenue: 240,
      quantity: 2,
      orders: 1,
      price: 120,
      rank: 2,
      isTop10: false,
      isBottom10: false
    },
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 203.8,
      quantity: 5,
      orders: 1,
      price: 40.76,
      rank: 3,
      isTop10: false,
      isBottom10: false
    }
  ],
  masterWines: [
    { id: 1, name: 'Château Montclair', vintage: 2020 },  
    { id: 2, name: 'Domaine Leflaive', vintage: 2018 },   
    { id: 1, name: 'Château Montclair', vintage: 2020 }   
  ]
}
Incoming request: [Object: null prototype] { criteria: 'revenue' }
Wines data: {
  bestSellingWines: [
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 402.6,
      quantity: 10,
      orders: 1,
      price: 40.26,
      rank: 1,
      isTop10: true,
      isBottom10: false
    },
    {
      masterWineId: 2,
      name: 'Domaine Leflaive',
      vintage: 2018,
      revenue: 240,
      quantity: 2,
      orders: 1,
      price: 120,
      rank: 2,
      isTop10: false,
      isBottom10: false
    },
    {
      masterWineId: 1,
      name: 'Château Montclair',
      vintage: 2020,
      revenue: 203.8,
      quantity: 5,
      orders: 1,
      price: 40.76,
      rank: 3,
      isTop10: false,
      isBottom10: false
    }
  ],
  masterWines: [
    { id: 1, name: 'Château Montclair', vintage: 2020 },  
    { id: 2, name: 'Domaine Leflaive', vintage: 2018 },   
    { id: 1, name: 'Château Montclair', vintage: 2020 }   
  ]
}

// server.ts

import Fastify from 'fastify';
import cors from '@fastify/cors';
import { setupDatabase, getBestSellingWines } from './data';

const fastify = Fastify();

fastify.register(cors, {
  origin: 'http://localhost:5173',
  methods: ['GET'],
  allowedHeaders: ['Content-Type'],
});

interface QueryParams {
  criteria?: 'revenue' | 'quantity' | 'orders';
  searchTerm?: string;
}

fastify.get<{ Querystring: QueryParams }>('/api/best-selling-wines', async (request, reply) => {
  console.log('Incoming request:', request.query);
  const { criteria = 'revenue', searchTerm = '' } = request.query;
  try {
    const wines = await getBestSellingWines(criteria, searchTerm);
    console.log('Wines data:', wines);
    reply.header('Content-Type', 'application/json').send({ bestSellingWines: wines.bestSellingWines });
  } catch (error) {
    console.error('Error fetching wines:', error);
    reply.code(500).header('Content-Type', 'application/json').send({ error: 'An error occurred', details: error.message });
  }
});

setupDatabase()
  .then(() => {
    console.log('Database setup complete');
    fastify.listen({ port: 3000, host: 'localhost' }, (err, address) => {
      if (err) {
        console.error('Server listen error:', err);
        process.exit(1);
      }
      console.log(`Server listening at ${address}`);
    });
  })
  .catch((err) => {
    console.error('Error setting up database:', err);
  });

 


Answers (3)