DEV Community

Ilyoskhuja
Ilyoskhuja

Posted on

Interactive matcher with vuejs

When you apply to a new job as a front-end developer, you can get any type of interview and some tasks from some level of the interview process. Nowadays we have 2 kinds of tasks "many popular test (interview) tasks" and "not popular test tasks" for frontend developers.BTW many companies think that test tasks from their companies are unique, and they ask that you(candidate) keep it secret and you will not publish a public GitHub repo. But when your search keywords of the task, in many cases you can find complete GitHub public projects with the same task with the same API.. so on. Let's solve this task interactive matcher from interview tasks with vuejs and you can find the complete project from this public GitHub repo.
We will create new vuejs project, inside this project we create assets folder with 2 cvs file 1 is "sound_recordings.cvs" 2 is "sound_recordings_input_report.cvs".
For working with State management we will create store.js inside the project src folder and we will add the code below:

import Vue from "vue";
import Vuex from "vuex";
import recordingsdata from "./assets/sound_recordings.csv";

import inputsdata from "./assets/sound_recordings_input_report.csv";
Vue.use(Vuex);

const appendId = (tempArray) => {
  return tempArray.map((item) => ({
    id: Math.random().toString().slice(2),
    ...item,
  }));
};

const postRecordingsData = appendId(recordingsdata);
const postInputs = appendId(inputsdata);

export const store = new Vuex.Store({
  state: {
    // origin
    recordings: postRecordingsData,

    // left aside list
    inputs: postInputs,

    // right aside list
    results: postRecordingsData,

    selectedInputsItem: {},
    selectedResultsItem: {},
  },
  mutations: {
    SET_STATE(state, payload) {
      Object.keys(payload).forEach((key) => {
        if (key in state) {
          state[key] = payload[key];
        }
      });
    },
    S_INPUT(state, payload) {
      state.selectedInputsItem = payload;
    },
    addInput(state) {
        console.log("state.selectedInputsItem:", state.selectedInputsItem);
    state.recordings.push(state.selectedInputsItem.item);
    state.results.push(state.selectedInputsItem.item)
    console.log("state:",state);    
    },
  },
});

Enter fullscreen mode Exit fullscreen mode

and inside App.vue file add the code below:

<template>
  <div id="app">
    <Header />
    <div class="container">
      <div class="row">
        <div class="col-md-5">
          <Inputs />
        </div>
        <div class="col-md-2">
          <Actions />
        </div>
        <div class="col-md-5">
          <Database />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Header from "./components/Header.vue";
import Inputs from "./components/inputs/Inputs.vue";
import Actions from "./components/actions/Actions.vue";
import Database from "./components/database/Database.vue";

export default {
  name: "App",
  components: {

    Header,
    Inputs,
    Actions,
    Database,
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #181c20;
  /* margin-top: 60px; */
}
</style>

Enter fullscreen mode Exit fullscreen mode

In the component folder, we will create Inputs, Database, and Actions components, Actions add the code below:

<template>
 <div>
  <button class="btn btn-outline-primary" @click="register"><i class="fa fa-arrow-right"></i> Register</button>
  </div>
</template>
<style scoped>
</style>
<script>

import { mapMutations } from "vuex";
export default {

  methods: {
    ...mapMutations(["SET_STATE"]),

    register() {
      console.log("selected:----",this.$store.state.selectedInputsItem);
      this.$store.commit('addInput')

    },
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

For Database component code like this:

<template>
  <div>
    <input type="text" v-model="search" placeholder="Search title.." />

    <div>Records: {{ recordings.length }}</div>
    <ul class="list-group list-group-flush">
      <li class="mt-4" v-for="item in recordings" :key="item.id">
        <div class="card">
          <div class="card-body">
            <h5 style="">{{ item.title }}</h5>
            <p>{{ item.artist }}</p>
            <div style="display: flex; justify-content: space-between">
              <h6>{{ item.isrc }}</h6>
              <h6>{{ item.duration | formatTime }}</h6>
            </div>
          </div>
        </div>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  data() {
    return {
      search: "",
    };
  },
  computed: {
    recordings() {
      const searchrg=new RegExp(this.search,'i');
      return this.$store.state.results.filter((item) =>
        [item.isrc, item.artist, item.title].some((el) =>
          el && el.toLowerCase().match(searchrg)
        )
      );
    },
  },

  filters: {
    formatTime(time) {
      if (time > 0) {
        var mins = ~~((time % 3600) / 60);
        var secs = ~~time % 60;

        var ret = "";
        ret += "0" + mins + "m" + " " + (secs < 10 ? "0" : "");
        ret += "" + secs + "s";
        return ret;
      } else return "";
    },
  },
  methods: {

};
</script>
<style scoped>
ul {
  list-style-type: none;
  overflow: scroll;
  overflow-x: hidden;
  height: 80vh;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Finally for inputs add code below:

<template>
  <ul class="list-group list-group-flush">
    <div>Inputs: {{ inputs.length }}</div>
    <li class="mt-4" v-for="item in inputs" :key="item.id">
      <div class="card " v-bind:class="{isActive:activeItem===item}" @click="findMatch(item)">
        <div class="card-body">
          <h5 style="">{{ item.title }}</h5>
          <p>{{ item.artist }}</p>
          <div style="display: flex; justify-content: space-between">
            <h6>{{ item.isrc }}</h6>
            <h6>{{ item.duration | formatTime }}</h6>
          </div>
        </div>
      </div>
    </li>
  </ul>
</template>
<style scoped>
ul {
  list-style-type: none;
  overflow: scroll;
  overflow-x: hidden;
  height: 80vh;
}
.isActive{
  border:18px solid #e19eae ;
}
</style>
<script>
import { mapMutations } from "vuex";
export default {
  data() {
    return {
      activeItem:null
    };
  },
  computed: {
    inputs() {
      return this.$store.state.inputs;
    },
  },
  methods: {
    ...mapMutations(["SET_STATE","S_INPUT"]),

    findMatch(item) {
      console.log(item);
      this.activeItem=item;
     this.S_INPUT({item});


      const targetFields =(item.title.toUpperCase()+' '+item.artist.toUpperCase() +(item.isrc?' ' + item.isrc?.toUpperCase():'')).split(' ');


      const t = this.$store.state.recordings.filter((elem) => {
         const ele=(elem.title.toUpperCase()+' '+elem.artist.toUpperCase() +' '+elem.isrc?.toUpperCase()).split(' ');

         return ele.filter(field=> targetFields.includes(field)).length>0;



      this.SET_STATE({
        results: t || [],
      });

    },
  },
  filters: {
    formatTime(time) {
      if (time > 0) {
        var mins = ~~((time % 3600) / 60);
        var secs = ~~time % 60;

        var ret = "";
        ret += "0" + mins + "m" + " " + (secs < 10 ? "0" : "");
        ret += "" + secs + "s";
        return ret;
      } else return "";
    },
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

When you run the project you can see it in the browser tab image below.
Image description

Image description

Image description

I hope this article helps you to pass the interview process.

Top comments (0)