File size: 6,552 Bytes
d491dc1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import React, { useState, useEffect } from 'react';
import * as API from '../api.js';

export default function DineoutSniperView({ onBack }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [mode, setMode] = useState('sniper'); // 'sniper' or 'grid'

  useEffect(() => {
    API.fetchDineoutSniper().then((res) => {
      if (res && res.venues) setData(res);
      setLoading(false);
    });
  }, []);

  return (
    <div className="min-h-screen bg-[#07070B] text-white p-6 md:p-12 font-sans selection:bg-[#FF3366]">
      
      {/* Top Header */}
      <div className="max-w-6xl mx-auto flex items-center justify-between mb-8 pb-6 border-b border-white/10">
        <div className="flex items-center gap-4">
          <button 
            onClick={onBack}
            className="p-2.5 rounded-full bg-white/[0.05] border border-white/15 text-white/80 hover:text-white hover:bg-white/10 transition-all cursor-pointer"
          >
            <span className="material-symbols-outlined text-xl">arrow_back</span>
          </button>
          <div>
            <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-amber-500/10 border border-amber-500/30 mb-1 font-mono">
              <span className="w-2 h-2 rounded-full bg-amber-500"></span>
              <span className="text-[10px] font-bold tracking-widest text-amber-400 uppercase">MODULE 4 • DINEOUT SLOT SNIPER</span>
            </div>
            <h1 className="text-3xl md:text-4xl font-serif font-bold text-white tracking-tight">
              Dineout Slot Sniper <span className="italic font-serif text-amber-400">Scored.</span>
            </h1>
          </div>
        </div>
      </div>

      {/* Industry Differentiation Showcase Card */}
      <div className="max-w-6xl mx-auto mb-8 bg-[#101018]/90 border border-white/10 rounded-3xl p-6 backdrop-blur-2xl space-y-4">
        <div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
          <div>
            <div className="flex items-center gap-2 mb-1">
              <span className="text-xs font-bold font-mono text-amber-400 uppercase tracking-wider">HYPERFLOW ARCHITECTURAL DIFFERENTIATION</span>
              <span className="px-2.5 py-0.5 rounded-full text-[10px] font-bold font-mono bg-amber-500/20 text-amber-300 border border-amber-500/30">
                DYNAMIC SLOT PRESSURE SCORING
              </span>
            </div>
            <h3 className="text-lg font-serif font-bold text-white">Dynamic Slot Pressure Velocity vs Static Booking Grids</h3>
            <p className="text-xs text-white/60 font-light max-w-2xl mt-1">
              Standard booking apps show unranked, static availability grids. HyperFlow evaluates real-time dining velocity (rating, peak hours, weekend factors) to score slot pressure and estimate exact fill time in minutes.
            </p>
          </div>

          <div className="flex items-center gap-2 bg-white/[0.05] p-1.5 rounded-full border border-white/10 shrink-0 font-mono">
            <button
              onClick={() => setMode('sniper')}
              className={`px-4 py-1.5 rounded-full text-xs font-bold transition-all cursor-pointer ${
                mode === 'sniper'
                  ? 'bg-gradient-to-r from-amber-500 to-orange-500 text-black shadow-md font-bold'
                  : 'text-white/60 hover:text-white'
              }`}
            >
              HyperFlow Slot Sniper
            </button>
            <button
              onClick={() => setMode('grid')}
              className={`px-4 py-1.5 rounded-full text-xs font-bold transition-all cursor-pointer ${
                mode === 'grid'
                  ? 'bg-red-500/30 text-red-300 border border-red-500/50 shadow-md'
                  : 'text-white/60 hover:text-white'
              }`}
            >
              Standard Static Grid
            </button>
          </div>
        </div>
      </div>

      <div className="max-w-6xl mx-auto space-y-6">
        {loading ? (
          <div className="py-20 text-center text-white/50 font-mono">Fetching Dineout slot predictions...</div>
        ) : (
          <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
            {(data?.venues || []).map((venue, i) => (
              <div key={i} className="bg-[#101018]/90 border border-white/10 rounded-3xl p-6 backdrop-blur-2xl space-y-5 flex flex-col justify-between">
                <div>
                  <div className="flex justify-between items-start mb-2">
                    <h3 className="text-lg font-serif font-bold text-white">{venue.venue_name}</h3>
                    <span className="text-xs font-mono text-amber-400 font-bold">RATING: {venue.rating}</span>
                  </div>
                  <p className="text-xs text-white/50 font-light">{venue.cuisine}</p>

                  <div className="mt-4 pt-4 border-t border-white/10 space-y-3">
                    <span className="text-xs text-white/40 uppercase font-mono">
                      {mode === 'sniper' ? 'SNIPED SLOT VELOCITY:' : 'STATIC AVAILABLE TIMES:'}
                    </span>
                    {venue.slots?.map((s, idx) => (
                      <div key={idx} className="p-3 bg-white/[0.04] border border-white/10 rounded-xl flex items-center justify-between text-xs">
                        <span className="font-bold text-white font-mono">{s.time_slot}</span>
                        {mode === 'sniper' ? (
                          <div className="text-right">
                            <p className="text-amber-400 font-mono font-bold">Fills in ~{s.estimated_minutes_to_full}m</p>
                            <span className="text-[10px] text-white/40 uppercase font-mono">Demand: {s.demand_score}</span>
                          </div>
                        ) : (
                          <span className="text-white/50 font-mono">Available</span>
                        )}
                      </div>
                    ))}
                  </div>
                </div>

                <button 
                  onClick={() => alert(`Slot booked at ${venue.venue_name}!`)}
                  className="w-full py-3 bg-gradient-to-r from-amber-500 to-orange-500 hover:opacity-90 text-black font-mono font-bold rounded-full text-xs transition-all cursor-pointer mt-4"
                >
                  Snipe Slot Now
                </button>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}