File size: 4,660 Bytes
964fb13
 
99a2718
 
 
 
 
 
 
cfbfed3
964fb13
50f9fbd
 
 
 
 
 
 
cfbfed3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3845801
cfbfed3
 
 
 
 
 
 
964fb13
 
cfbfed3
 
 
 
 
 
 
 
 
50f9fbd
 
 
 
 
 
cfbfed3
 
 
 
 
3845801
 
cfbfed3
964fb13
50f9fbd
cfbfed3
50f9fbd
 
 
 
 
 
cfbfed3
 
 
 
 
 
 
 
964fb13
50f9fbd
cfbfed3
50f9fbd
 
 
 
 
 
cfbfed3
 
 
 
 
 
 
 
964fb13
50f9fbd
cfbfed3
3845801
50f9fbd
 
 
 
 
 
 
 
727eb79
 
cfbfed3
50f9fbd
964fb13
 
 
 
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
// frontend/src/components/admin/AIInsightBox.jsx
import React from "react";
import {
  Sparkles,
  TrendingUp,
  AlertTriangle,
  Users as UsersIcon,
  Lightbulb,
} from "lucide-react";
import { differenceInDays } from "date-fns";

export default function AIInsightBox({
  memberships = [],
  onRenewingSoonClick,
  onNeedAttentionClick,
  onGoodStandingClick,
  onSuggestionClick,
}) {
  const now = new Date();

  const totalMembers = memberships.length;

  const renewingSoon = memberships.filter((m) => {
    if (m.status !== "active" || !m.renewal_date) return false;
    const days = differenceInDays(new Date(m.renewal_date), now);
    return days >= 0 && days <= 14;
  }).length;

  const needAttention = memberships.filter((m) => {
    if (!m.renewal_date) return false;
    const days = differenceInDays(new Date(m.renewal_date), now);
    return m.status === "expired" || days < 0;
  }).length;

  const goodStanding = memberships.filter((m) => m.status === "active").length;

  const suggestionText =
    totalMembers === 0
      ? "Once members join, I’ll highlight who needs your attention first."
      : `Focus on the ${needAttention} at-risk member${
          needAttention === 1 ? "" : "s"
        } this week to improve retention.`;

  return (
    <div className="mb-8 rounded-3xl border border-purple-200 bg-gradient-to-r from-purple-50 to-purple-100/70 px-4 py-5 sm:px-6 sm:py-6">
      <h2 className="text-sm font-semibold text-stone-900 mb-4 flex items-center gap-2">
        <span className="inline-flex items-center justify-center h-6 w-6 rounded-full bg-purple-100 text-purple-700">
          <Sparkles className="w-3 h-3" />
        </span>
        AI Assistant Insights
      </h2>

      <div className="space-y-3">
        {/* Row 1: renewing soon */}
        <button
          type="button"
          onClick={onRenewingSoonClick}
          className="w-full flex items-center justify-between rounded-2xl bg-white/90 px-4 py-3 shadow-sm hover:shadow-md transition-shadow cursor-pointer text-left"
        >
          <div className="flex items-center gap-3">
            <div className="h-8 w-8 rounded-full bg-emerald-50 flex items-center justify-center">
              <TrendingUp className="w-4 h-4 text-emerald-600" />
            </div>
            <p className="text-sm text-stone-700">
              {renewingSoon} member{renewingSoon === 1 ? "" : "s"} are due for
              renewal in the next 2 weeks
            </p>
          </div>
        </button>

        {/* Row 2: need attention */}
        <button
          type="button"
          onClick={onNeedAttentionClick}
          className="w-full flex items-center justify-between rounded-2xl bg-white/90 px-4 py-3 shadow-sm hover:shadow-md transition-shadow cursor-pointer text-left"
        >
          <div className="flex items-center gap-3">
            <div className="h-8 w-8 rounded-full bg-amber-50 flex items-center justify-center">
              <AlertTriangle className="w-4 h-4 text-amber-600" />
            </div>
            <p className="text-sm text-stone-700">
              {needAttention} member{needAttention === 1 ? "" : "s"} need
              immediate attention for renewal
            </p>
          </div>
        </button>

        {/* Row 3: good standing */}
        <button
          type="button"
          onClick={onGoodStandingClick}
          className="w-full flex items-center justify-between rounded-2xl bg-white/90 px-4 py-3 shadow-sm hover:shadow-md transition-shadow cursor-pointer text-left"
        >
          <div className="flex items-center gap-3">
            <div className="h-8 w-8 rounded-full bg-blue-50 flex items-center justify-center">
              <UsersIcon className="w-4 h-4 text-blue-600" />
            </div>
            <p className="text-sm text-stone-700">
              {goodStanding} active member{goodStanding === 1 ? "" : "s"}{" "}
              maintaining good standing
            </p>
          </div>
        </button>

        {/* Row 4: suggestion */}
        <button
          type="button"
          onClick={onSuggestionClick}
          className="mt-3 w-full rounded-2xl bg-purple-100 px-4 py-3 text-left hover:bg-purple-200/80 transition-colors cursor-pointer flex items-center gap-2"
        >
          <span className="inline-flex h-7 w-7 items-center justify-center rounded-full bg-yellow-100">
            <Lightbulb className="w-4 h-4 text-yellow-500" />
          </span>
          <p className="text-sm text-purple-900">
            <span className="font-semibold">Suggestion:</span> {suggestionText}
          </p>
        </button>
      </div>
    </div>
  );
}