Untitled

mail@pastecode.io avatar
unknown
javascript
a year ago
7.5 kB
2
Indexable
Never
'use client';

import { useEffect, useState } from "react";
import data from './data.json';

export default function Page() {
  return (
    <MainComponent>
      <HeaderComponent/>
      <TableComponent/>
    </MainComponent>
  )
}

function MainComponent({children}:{children:React.ReactNode}){
  return (
    <div className="flex flex-col items-center">
      {children}
    </div>
  )
}

function HeaderComponent(){
  return (
    <div className="bg-[#F45B69] flex h-12 w-full justify-around ">
      <div className="flex flex-row child:flex-1 items-center w-full divide-x divide-slate-600 text-white">
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
          <path strokeLinecap="round" strokeLinejoin="round" d="M12 10.5v6m3-3H9m4.06-7.19l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" />
        </svg>
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
          <path strokeLinecap="round" strokeLinejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
        </svg>
        <div className=" text-center ">Prev</div>
        <div className=" text-center ">Current</div>
        <div className=" text-center ">Next</div>
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
          <path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
        </svg>
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
          <path strokeLinecap="round" strokeLinejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
          <path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
        </svg>
      </div>
    </div>
  )
}

function TableComponent(){
  const hours = [8,9,10,11,12,13,14,15,16,17,18,19,20,21,22];

  return (
    <div className="bg-[#2e3f45] text-white w-full p-5 pb-3">
      <div className="flex flex-col">
        <div className="flex flex-row ">
          <div className="w-10 flex-none"></div>
          <div className="flex flex-row w-full">
            {
              data.map(day => 
                <div key={day.id} className="flex-1 text-center font-bold">
                  <div className="">{day["day"].slice(0, 3)}</div>
                  <div className="mx-5 rounded-full border-2 ">{day["date"]}</div>
                  <div className="h-3 border-l-0.1"></div>
                </div> 
              )
            }
          </div>
        </div>
        <div className="flex flex-row">
          <div className="flex flex-col">
            {hours.map(hour =>
              <div key={hour} className="flex flex-row h-12">
                <div className="w-8 text-right pr-1 relative bottom-3 text-sm">{hour}u</div>
                <div className="w-2 border-t-0.1"></div>
              </div>
            )}
          </div>
          <div className="flex flex-row w-full">
            {
              data.map(day =>
                <div key={day.id} className="flex-1 grid grid-cols-1">
                  {hours
                  .filter(hour => !day.timeslots.some(timeslot => timeslot.start < hour && hour < timeslot.end ))
                  .map((hour, i, arr) => 
                  <div key={hour} className={`border-t-0.1 border-l-0.1 h-full  ${rowspan(arr[i+1] - hour)}`}>
                    {day.timeslots.filter(timeslot => (timeslot.start == hour)).map(timeslot => <TimeslotComponent key={timeslot.id} title={timeslot.title} names={timeslot.names}/> )}
                  </div>)
                  }
                </div>
                )
            }
          </div>
        </div>
      </div>
    </div>
  )
}

function TimeslotComponent({title, names}:{title:string, names:string[]}){
  const myName = "Saba"
  const [available, setAvailable] = useState(!!names.includes(myName));
  const [show, setShow] = useState(false);

  useEffect(() => {
    if (available) {
      if (!names.includes(myName)){
        names.push(myName)
      }
    }else {
      names.splice(names.findIndex(name => name == myName), 1)
    }
  }, [available])

  return (
    <div className="relative z-1 h-full">
      <div className="absolute right-0 left-0 top-0  p-0.5  bg-zinc-50 m-0.5">
        <div className=" pt-0 p-1 lg:text-sm text-xs font-mono rounded-lg rounded-bl-none rounded-tr-none rounded-tl-none  min-h-full w-full  bg-[#7c4145]" onMouseEnter={() => setShow(true)} onMouseLeave={() => setShow(false)} >
          <div className="lg:flex justify-between">
            <div className="font-white font-semibold capitalize lg:underline underline-offset-4 decoration-pink-500 decoration-2 lg:mt-1">{title}</div>
            <IsAvailableButton available={available} setAvailable={setAvailable}/>
          </div>
          {show && <div className=" capitalize">{names.map(name => <div className="block">{name}</div>)}</div>}
        </div>
      </div>
      <div className="bg-[#3F565F] w-1 ml-0.5 h-full z-0">
      </div>
    </div>
    
  )
}

function IsAvailableButton({available, setAvailable}:{available:boolean, setAvailable:React.Dispatch<React.SetStateAction<boolean>>}){
  if (available) {
    return <button className="bg-green-500  border-transparent text-white font-semibold px-1 lg:mt-1 border rounded hover:border-green-500 hover:bg-transparent hover:text-green-700" onClick={() => setAvailable(false)}>Free</button>
  }else{
    return <button className="bg-red-500    border-transparent text-white font-semibold px-1 lg:mt-1 border rounded hover:border-red-500   hover:bg-transparent hover:text-red-700" onClick={() => setAvailable(true)}>Busy</button>
  }
}






function rowspan(i:number){
  const rowspans = [
    'row-span-1','row-span-2','row-span-3','row-span-4','row-span-5','row-span-6','row-span-7','row-span-8',
    'row-span-9','row-span-10','row-span-11','row-span-12','row-span-13','row-span-14','row-span-15','row-span-16',
    'row-span-17','row-span-18','row-span-19','row-span-20','row-span-21','row-span-22','row-span-23','row-span-24'
  ];
  return rowspans[i-1];
}