Coder Social home page Coder Social logo

motify's Introduction

Motify: A Fullstack Spotify Clone

Motify is a full-stack clone of Spotify designed to emulate the core functionalities of the original platform with a responsive and intuitive user interface.

Motify Overview

Tech Stack

The Motify application employs a modern full-stack architecture:

  • React.js

React

- Ruby on Rails with PostgreSQL

Rails

PostgreSQL

- Redux

Redux

- Node.js

Nodejs

- HTML, CSS, Vanilla JavaScript

html5

css3

javascript

Data Architecture

motify-data-structure.png

The front end is built with React, leveraging HTML, CSS, and JavaScript to deliver a responsive user interface and user experience. State management within the front end is handled by Redux, which serves as a predictable state container, interfacing with middleware for asynchronous events.

Routing is managed through a combination of React for component rendering and Node.js for server-side logic, facilitating the navigation within the application.

The backend is powered by Ruby on Rails, providing a robust server-side framework. Data persistence is achieved with PostgreSQL, a powerful object-relational database system. The data serialization is handled by jBuilder, allowing for the creation of JSON structures that are consumed by the front end.

This architecture supports a scalable, maintainable, and interactive web application, designed for optimal user engagement and straightforward data flow from the database to the end user.

Core Features

  • Play Bar: Interactive play bar for music playback and controls.

  • Playlist Management: Comprehensive playlist management, including CRUD operations, song addition/removal, and custom playlist titles.

  • Hosting: Application deployment on Render.

html5


  • Dynamic Search: Real-time search across artists, songs, albums, and playlists. Dynamic Search

  • User Authentication: Secure login, registration, and session management with demo account access. Motify Signup Flow Motify Signup Flow

UI/UX Design Philosophy

Spotify's design philosophy revolves around ;

Highlighted Features

Dynamic Search

Dynamic real-time search fetching from Rails backend for Songs, Albums, Artists, and Playlists that match the search query.

Dynamic Search

import { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import searchIcon from '../../static/icons/search-inactive.svg';
import closeIcon from '../../static/icons/close.svg';
import { performSearch, clearSearch } from '../../store/search';
import SearchResultsDropdown from './SearchResultsDropdown';

const SearchField = () => {
  const [inputValue, setInputValue] = useState('');
  const dispatch = useDispatch();
  const { error, results, searchInitiated, query } = useSelector(state => state.search);

  const handleChange = (event) => {
    const newQuery = event.target.value;
    setInputValue(newQuery);
    if (newQuery) {
      dispatch(performSearch(newQuery)); // Dispatching performSearch action with new query
    } else {
      dispatch(clearSearch()); // Clearing the search when input is empty
    }
  };

  const clearInput = () => {
    setInputValue('');
    dispatch(clearSearch()); // Dispatch Redux action to clear search
  };

  return (
    <>
      <div className='search-input-container'>
        <img src={searchIcon} alt='Search' className="search-icon"/>
        <input
          type='text'
          placeholder='Search for songs or episodes'
          value={inputValue}
          onChange={handleChange}
        />
        <img src={closeIcon} alt='Close' className='close-icon' onClick={clearInput}/>
      </div>
      {error && <p>Error: {error.message}</p>}
      <SearchResultsDropdown query={query} searchResults={results} searchInitiated={searchInitiated}/>
    </>
  );
}

export default SearchField;

SongsTable UI/UX with Redux State Management

Redux state management for globalized state enhancing user experience and user interface design. Song row style changes based on current song playing state.

Song State Redux

import { useSelector, useDispatch } from 'react-redux';
import { useState } from 'react';
import { receiveSong, togglePlay } from '../../store/audioActions'; // Import relevant actions
import { ReactSVG } from 'react-svg';
import lilPlayButton from '../../static/icons/noun-play-1009801.svg'

const SongsTable = () => {
  const dispatch = useDispatch();
  const currentAlbum = useSelector(state => state.audio.currentAlbum);
  const [hoveredTrack, setHoveredTrack] = useState(null);
  // Function to handle play button click
  const handlePlaySong = (song) => {
    dispatch(receiveSong(song));
    dispatch(togglePlay());
  };
  return (
    <div className='show-songs-table'>
      {
        currentAlbum.songs?.map((song, trackNum) =>
          <>
            <div
              className='show-songs-row-container'
              onMouseEnter={() => setHoveredTrack(trackNum)}
              onMouseLeave={() => setHoveredTrack(null)}
              onClick={() => handlePlaySong(song)} // ! This is what changes the Redux State
            >
              <div className='row-start'
              >
                <div className='track-num'>
                  {hoveredTrack === trackNum 
                    ?
                    (<ReactSVG src={lilPlayButton} className='anim-play-button' />)
                    :
                    (<p style={{'width':'12px', 'height':'12px'}}>{trackNum + 1}</p>)
                  }
                </div>
                <div className='song-title-artist-container'>
                  <p className='song-title'>{song.title}</p>
                  <p className='song-title-artist-name'>{currentAlbum.artistName}</p>
                </div>
                <div className='song-title-artist-container'>
                  <p className='song-title'>{song.album?.title}</p>
                </div>
              </div>

              <div className='row-end'>
                <div className='like-button-duration'>
                  <p className='duration-text header-time'>{`${Math.floor(song.duration / 60)}:${String(song.duration % 60).padStart(2, '0')}`}</p>
                </div>
              </div>

            </div>
          </>
        )
      }
    </div>
  )
}

export default SongsTable

Future Features

  • Enhanced user and artist profiles.
  • Social features to follow and unfollow users and artists.
  • Like/unlike functionality for songs, albums, and playlists.
  • Dynamic playlist cover generation based on song selection.

motify's People

Contributors

garysbot avatar

Stargazers

 avatar KAZOOKIovestocode avatar

Watchers

 avatar

motify's Issues

Frontend Routes

Frontend Routes

  • Frontend routes contains wildcard variables written in camelCase
  • Correctly formatted
    • Routes are displayed with inline coding text (backticks)

Bugs / Console

Timeline: M 12/18 - SU 12/24
Due SA 12/23

  • ContentCards.jsx line 109 add key to outer element
  • SearchResultsDropdown.jsx line 55 add key to outer element
  • ArtistResultsPage.jsx line 55 add key to outer element
  • PlaylistCreate.jsx line 92 add key to outer element
  • / on load it goes to a playlist page instead of staying on /
  • Auto plays whenever you go to Album or Playlist
  • Doesn’t continue next song on it’s own
  • When a song is playing and you click another song, it stops your current song but doesn’t play the next song
  • When a song is playing the song row container should be grayed in
  • Playlist title edit doesn't save in redux and render. Does save in backend rails though.
  • Sign out requires double refresh

Wiki Home Page

Wiki Home Page

  • Is the first page you see upon entering the wiki
  • Contains a welcome message
  • Contains a link/placeholder for a link to the live page
  • All links in the right sidebar should contain each wiki page and link to the correct page
  • Correctly formatted
    • each wiki page is listed in bullet points
    • all links route the correct page

ShowPlaylist `Add` button state and Rails backend logic

  • Album Results Dropdown ln 127
  {
    albumResults.map((album, index) =>
      <>
        <div 
          className='result-row' 
          style={index === 0 ? { marginTop: '2rem' } : {}}
          onClick={() => toggleSongsDisplay(album.id)}>
          <div className='result-detail'>
            <img src={album.coverImg} alt='' className='result-album-img' />
            <div className='name'>
              <p key={index}>{album.title}</p>
              <p className='result-label'>Album</p>
            </div>
          </div>
          <div className='result-link'>
            <img src={searchArrow} alt='Link' className='search-arrow'/>
          </div>
        </div>
        {isAlbumExpanded(album.id) && <AlbumResultPage songs={album.songs} />}
      </>
    )
  }
  • Song Result Dropdown ln 150
{
        songResults.map((song, index) => 
          <div 
            className='result-row'
            style={index === 0 ? { marginTop: '2rem' } : {}}
          >
            <div className='result-detail song-result'>
                <img src={song.coverImg} alt='' className='result-song-img'/>
                <div className='name'>
                  <p key={index}>{song.title}</p>
                  <Link to={`artists/${song.artistId}`} className='result-album'><p className='result-label'>{song.artistName}</p></Link>
                </div>
            </div>
            <div className='result-album'>
              <Link><p>{song.albumTitle}</p></Link>
            </div>
            <div className='result-link'>
              <button>Add</button>              
              {/* ! Need a handler to add to the playlist here */}
            </div>
          </div>
        )
      }

MVP List

MVP List

  • Should have 7 Features.
    • 3 of those are User Auth, Render, and Production README.
    • The other 4 are from the MVP List or they have clarified them with you
  • Contains a description sentence of the app
  • Includes two to three detailed bullets on functionality and presentation of feature
  • At least one CRUD feature, which states what CRUD operations are planned (creation, reading, updating, deletion)
  • Estimates how long it will take the code each MVP
  • Correctly formatted
    • MVPs are listed in an ordered list
    • Each MVP is broken down into bullet points

Playlists

Timeline: M 12/18 - SU 12/24

Backend

  • Playlist Create
  • Playlist Show
  • Playlist Update
  • Playlist Delete

Redux

  • Playlist Create
  • Playlist Show
  • Playlist Update
  • Playlist Delete - due TH 12/21

Frontend

  • Playlist Create - due W 12/20
  • Playlist Show - due T 12/19
  • Playlist Update
  • Playlist Delete - due W 12/20
  • UserHomeContent - style Playlist cards - due F 12/22

PlayBar Detailed Styling

  • Hover opacity changes to the buttons
  • Time position text
  • hover on track position → white to green color + add circle on current position
  • volume → on hover white to green color + add circle on current position
  • when current song img is empty there’s a white border around it
  • ShowPages Bonus → double click changes track number to play animation

Backend Routes

Backend Routes

  • Contains the following sections: HTML, API Endpoints(Backend)
  • Each route has a description
  • API Endpoint routes contains wildcard variables written in snake_case
  • Routes does not contain superfluous routes
  • Have API routes that will allow the front end to get all info it needs and does not have unneeded routes:
    • probably doesn’t need a GET likes api endpoint because that info comes through the post show

Sample State

Sample State

  • State shape is flat!
  • State’s keys are camelCased
  • All keys within the values in the state are accessible in the schema
  • Correctly formatted
    • Sample state is rendered with triple backticks, and the language ```javascript...```). This will display the state as a code block instead of a giant line of text
    • Top level slices
      • entities
      • session
      • errors (here or in ui)
      • ui (if needed)
    • Should NOT have nested slices, aka comments inside of posts
    • Some info from other tables is ok, for instance:
    • the author username and imageurl for a post. basically any info that the user can’t change
    • like count and a boolean on whether the user likes the post instead of a likes slice

ShowPages

  • Update hover active and inactive song bar
    image

PlayBar

Timeline: M 12/18 - SU 12/24

  • Backend
  • Redux
  • Frontend Components
  • #16
  • Play song upon card click from UserContent
  • Add github, portfolio, linkedin urls

Search

Timeline: M 12/18 - SU 12/24

  • Backend
  • Frontend
  • Redux
  • Integrated in PlaylistCreate
  • #14

SearchResultsDropdown.jsx

Database Schema

Database Schema

  • Contains correct datatypes
  • Contains appropriate constraints/details
    • primary key
    • not null
    • unique
    • indexed
    • foreign key
  • Contains bullet points after the table that state which foreign keys will reference to which table, or references to the associations which will be made
  • foreign key and table name are lowercased, snake_cased and back_ticked
  • Correctly formatted
    • schema is written in a table format
    • the table’s name are lowercased, snake_cased and back_ticked
    • the table header column names are bolded
    • columns names are lowercased and snaked_cased and back_ticked

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.