|
2 | 2 | * favorites.js — 즐겨찾는 음료(최대 3개) 목록을 GET /users/me/drinks/로 채우고, |
3 | 3 | * "추가"/"수정" 오버레이(종류→브랜드→메뉴→사이즈→아이콘)로 선택한 프리셋을 |
4 | 4 | * POST .../from-preset/(추가) 또는 PATCH .../<id>/(교체)로 저장한다. |
| 5 | + * 브랜드 단계에서 "직접입력"을 고르면 메뉴/사이즈 프리셋 단계 대신 자유 입력 |
| 6 | + * 폼으로 가고, POST/PATCH .../drinks/(직접입력 전용 엔드포인트)로 저장한다. |
5 | 7 | */ |
6 | 8 | (function () { |
7 | 9 | const listEl = document.getElementById('favorite-drinks-list'); |
|
14 | 16 | brand: overlay.querySelector('[data-step="2"]'), |
15 | 17 | menu: overlay.querySelector('[data-step="3"]'), |
16 | 18 | size: overlay.querySelector('[data-step="4"]'), |
| 19 | + custom: overlay.querySelector('[data-step="custom"]'), |
17 | 20 | icon: overlay.querySelector('[data-step="5"]'), |
18 | 21 | }; |
19 | 22 |
|
| 23 | + const customBrandInput = document.getElementById('custom-brand-input'); |
| 24 | + const customNameInput = document.getElementById('custom-name-input'); |
| 25 | + const customSizeInput = document.getElementById('custom-size-input'); |
| 26 | + const customCaffeineInput = document.getElementById('custom-caffeine-input'); |
| 27 | + const customNextBtn = document.getElementById('wizard-custom-next-btn'); |
| 28 | + |
20 | 29 | let wizard = { |
21 | 30 | mode: 'add', editingId: null, |
22 | 31 | type: null, brand: null, name: null, size: null, iconKey: null, |
| 32 | + customBrandName: '', caffeineMg: null, |
23 | 33 | presetsForType: [], |
24 | 34 | }; |
25 | 35 |
|
|
123 | 133 | wizard = { |
124 | 134 | mode, editingId: editingId ?? null, |
125 | 135 | type: null, brand: null, name: null, size: null, iconKey: null, |
| 136 | + customBrandName: '', caffeineMg: null, |
126 | 137 | presetsForType: [], |
127 | 138 | }; |
128 | 139 | steps.type.querySelectorAll('.option_item').forEach((el) => el.classList.remove('is-selected')); |
129 | 140 | clearOptionList(steps.brand); |
130 | 141 | clearOptionList(steps.menu); |
131 | 142 | clearOptionList(steps.size); |
132 | 143 | clearOptionList(steps.icon); |
| 144 | + customBrandInput.value = ''; |
| 145 | + customNameInput.value = ''; |
| 146 | + customSizeInput.value = ''; |
| 147 | + customCaffeineInput.value = ''; |
133 | 148 | showStep('type'); |
134 | 149 | overlay.style.display = 'flex'; |
135 | 150 | } |
|
144 | 159 |
|
145 | 160 | const seen = new Map(); |
146 | 161 | wizard.presetsForType.forEach((p) => { if (!seen.has(p.brand)) seen.set(p.brand, p.brand_name); }); |
147 | | - renderOptionList(steps.brand, [...seen.entries()].map(([value, label]) => ({ value, label })), (value) => { |
| 162 | + const options = [...seen.entries()].map(([value, label]) => ({ value, label })); |
| 163 | + options.push({ value: 'custom', label: '직접입력' }); |
| 164 | + renderOptionList(steps.brand, options, (value) => { |
148 | 165 | wizard.brand = value; |
149 | 166 | }); |
150 | 167 | } |
|
187 | 204 |
|
188 | 205 | async function saveDrink() { |
189 | 206 | let res; |
190 | | - if (wizard.mode === 'add') { |
| 207 | + if (wizard.brand === 'custom') { |
| 208 | + const payload = { |
| 209 | + type: wizard.type, |
| 210 | + brand: 'custom', |
| 211 | + custom_brand_name: wizard.customBrandName, |
| 212 | + name: wizard.name, |
| 213 | + size: wizard.size, |
| 214 | + caffeine_mg: wizard.caffeineMg, |
| 215 | + icon_key: wizard.iconKey, |
| 216 | + is_favorite: true, |
| 217 | + }; |
| 218 | + res = wizard.mode === 'add' |
| 219 | + ? await apiFetch('/users/me/drinks/', { method: 'POST', body: JSON.stringify(payload) }) |
| 220 | + : await apiFetch(`/users/me/drinks/${wizard.editingId}/`, { method: 'PATCH', body: JSON.stringify(payload) }); |
| 221 | + } else if (wizard.mode === 'add') { |
191 | 222 | res = await apiFetch('/users/me/drinks/from-preset/', { |
192 | 223 | method: 'POST', |
193 | 224 | body: JSON.stringify({ |
|
237 | 268 |
|
238 | 269 | steps.brand.querySelector('.next_btn').addEventListener('click', () => { |
239 | 270 | if (!wizard.brand) { alert('브랜드를 선택해주세요.'); return; } |
| 271 | + if (wizard.brand === 'custom') { |
| 272 | + showStep('custom'); |
| 273 | + return; |
| 274 | + } |
240 | 275 | loadMenuOptions(); |
241 | 276 | showStep('menu'); |
242 | 277 | }); |
243 | 278 |
|
| 279 | + customNextBtn.addEventListener('click', () => { |
| 280 | + const name = customNameInput.value.trim(); |
| 281 | + const caffeine = Number(customCaffeineInput.value); |
| 282 | + if (!name) { alert('음료 이름을 입력해주세요.'); return; } |
| 283 | + if (!customCaffeineInput.value || !(caffeine > 0 && caffeine <= 1000)) { |
| 284 | + alert('카페인 함량을 1~1000mg 사이로 입력해주세요.'); |
| 285 | + return; |
| 286 | + } |
| 287 | + wizard.customBrandName = customBrandInput.value.trim(); |
| 288 | + wizard.name = name; |
| 289 | + wizard.size = customSizeInput.value.trim(); |
| 290 | + wizard.caffeineMg = caffeine; |
| 291 | + loadIconOptions(); |
| 292 | + showStep('icon'); |
| 293 | + }); |
| 294 | + |
244 | 295 | steps.menu.querySelector('.next_btn').addEventListener('click', () => { |
245 | 296 | if (!wizard.name) { alert('메뉴를 선택해주세요.'); return; } |
246 | 297 | loadSizeOptions(); |
|
0 commit comments