File size: 3,290 Bytes
ef78361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""μ‚¬μ΄λ“œλ°” μ„€μ • λͺ¨λ“ˆ.

API Key 인증 + 캠페인 선택 UI.
"""
import os

import requests
import streamlit as st

from core.api_client import ChainShiftClient


def render_sidebar() -> tuple[dict, int, str] | None:
    """μ‚¬μ΄λ“œλ°” λ Œλ”λ§.

    Returns:
        (auth_info, campaign_id, campaign_display) λ˜λŠ” None (인증 μ‹€νŒ¨ μ‹œ)
        auth_info = {"api_key": str}
    """
    with st.sidebar:
        st.header("μ„€μ •")

        auth_info = _render_api_key_section()
        if not auth_info:
            return None

        st.divider()

        # 캠페인 선택
        result = _render_campaign_selector(auth_info)
        if not result:
            return None

        campaign_id, campaign_display = result
        return auth_info, campaign_id, campaign_display


def _render_api_key_section() -> dict | None:
    """API Key 인증 (env var μžλ™ 인증 λ˜λŠ” 직접 μž…λ ₯)."""
    env_api_key = os.environ.get("CHAINSHIFT_API_KEY", "")

    api_key = st.text_input(
        "API Key",
        type="password",
        placeholder="sk_live_xxx...",
        value=env_api_key,
        help="API Key 직접 μž…λ ₯ (ν™˜κ²½λ³€μˆ˜ CHAINSHIFT_API_KEY 지원)",
        key="direct_api_key",
    )
    if not api_key:
        st.info("API Keyλ₯Ό μž…λ ₯ν•˜μ„Έμš”")
        return None

    return {
        "api_key": api_key,
        "access_token": None,
        "email": None,
    }


# =============================================================================
# Campaign selector
# =============================================================================


def _render_campaign_selector(auth_info: dict) -> tuple[int, str] | None:
    """캠페인 선택 λ“œλ‘­λ‹€μš΄."""
    try:
        from core.data_fetchers import get_campaigns

        api_key = auth_info.get("api_key") or ""
        access_token = auth_info.get("access_token") or ""
        campaigns_response = get_campaigns(
            api_key=api_key, access_token=access_token
        )
        campaigns = campaigns_response.get("data", {}).get("items", [])

        if not campaigns:
            st.error("μΊ νŽ˜μΈμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€")
            return None

        # Sort campaigns by ID descending (latest first)
        campaigns_sorted = sorted(campaigns, key=lambda c: c.get("id", 0), reverse=True)

        def format_campaign(c):
            return f"{c['name']}  (#{c['id']})"

        st.markdown("**캠페인**")
        selected = st.selectbox(
            "캠페인 선택",
            options=campaigns_sorted,
            format_func=format_campaign,
            label_visibility="collapsed",
        )
        selected_campaign_id = selected["id"]
        selected_campaign_display = format_campaign(selected)

        st.caption(f"Campaign #{selected_campaign_id}")
        return selected_campaign_id, selected_campaign_display

    except requests.exceptions.ConnectionError:
        st.error("μ„œλ²„ 연결에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€. μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”.")
        return None
    except requests.exceptions.Timeout:
        st.error("μ„œλ²„ 응닡 μ‹œκ°„μ΄ μ΄ˆκ³Όλ˜μ—ˆμŠ΅λ‹ˆλ‹€. μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”.")
        return None
    except Exception as e:
        st.error(f"API 였λ₯˜: {str(e)}")
        return None